Rename source set "descriptor.loader.java" -> "descriptors.jvm"
The new name is more convenient and precise because this module is no longer only about loading declarations from Java, it also contains implementation of loading Kotlin declarations from .class files, as well as type mapping abstractions, JVM ABI specifications, etc.
This commit is contained in:
+3
@@ -0,0 +1,3 @@
|
||||
org.jetbrains.kotlin.load.java.FieldOverridabilityCondition
|
||||
org.jetbrains.kotlin.load.java.ErasedOverridabilityCondition
|
||||
org.jetbrains.kotlin.load.java.JavaIncompatibilityRulesOverridabilityCondition
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.serialization.jvm;
|
||||
|
||||
import "core/deserialization/src/ext_options.proto";
|
||||
import "core/deserialization/src/descriptors.proto";
|
||||
|
||||
option java_outer_classname = "JvmProtoBuf";
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
||||
message StringTableTypes {
|
||||
message Record {
|
||||
// The number of times this record should be repeated; this is used to collapse identical subsequent records in the list
|
||||
optional int32 range = 1 [default = 1];
|
||||
|
||||
// Index of the predefined constant. If this field is present, the associated string is ignored
|
||||
optional int32 predefined_index = 2;
|
||||
|
||||
// A string which should be used. If this field is present, both the associated string and the predefined string index are ignored
|
||||
optional string string = 6;
|
||||
|
||||
enum Operation {
|
||||
NONE = 0;
|
||||
|
||||
// replaceAll('$', '.')
|
||||
// java/util/Map$Entry -> java/util/Map.Entry;
|
||||
INTERNAL_TO_CLASS_ID = 1;
|
||||
|
||||
// substring(1, length - 1) and then replaceAll('$', '.')
|
||||
// Ljava/util/Map$Entry; -> java/util/Map.Entry
|
||||
DESC_TO_CLASS_ID = 2;
|
||||
}
|
||||
|
||||
// Perform a described operation on the string
|
||||
optional Operation operation = 3 [default = NONE];
|
||||
|
||||
// If this field is present, the "substring" operation must be performed with the first element of this list as the start index,
|
||||
// and the second element as the end index.
|
||||
// If an operation is not NONE, it's applied _after_ this substring operation
|
||||
repeated int32 substring_index = 4 [packed = true];
|
||||
|
||||
// If this field is present, the "replaceAll" operation must be performed with the first element of this list as the code point
|
||||
// of the character to replace, and the second element as the code point of the replacement character
|
||||
repeated int32 replace_char = 5 [packed = true];
|
||||
}
|
||||
|
||||
repeated Record record = 1;
|
||||
|
||||
// Indices of strings which are names of local classes or anonymous objects
|
||||
repeated int32 local_name = 5 [packed = true];
|
||||
}
|
||||
|
||||
message JvmMethodSignature {
|
||||
optional int32 name = 1 [(string_id_in_table) = true];
|
||||
|
||||
// JVM descriptor of the method, e.g. '(Ljava/util/List;)[Ljava/lang/Object;'
|
||||
optional int32 desc = 2 [(string_id_in_table) = true];
|
||||
}
|
||||
|
||||
message JvmFieldSignature {
|
||||
optional int32 name = 1 [(string_id_in_table) = true];
|
||||
|
||||
// JVM descriptor of the field type, e.g. 'Ljava/lang/String;'
|
||||
optional int32 desc = 2 [(string_id_in_table) = true];
|
||||
}
|
||||
|
||||
message JvmPropertySignature {
|
||||
optional JvmFieldSignature field = 1;
|
||||
|
||||
// Annotations on properties are written on a synthetic method with this signature
|
||||
optional JvmMethodSignature synthetic_method = 2;
|
||||
|
||||
optional JvmMethodSignature getter = 3;
|
||||
optional JvmMethodSignature setter = 4;
|
||||
}
|
||||
|
||||
extend Constructor {
|
||||
optional JvmMethodSignature constructor_signature = 100;
|
||||
}
|
||||
|
||||
extend Function {
|
||||
optional JvmMethodSignature method_signature = 100;
|
||||
}
|
||||
|
||||
extend Property {
|
||||
optional JvmPropertySignature property_signature = 100;
|
||||
}
|
||||
|
||||
extend Type {
|
||||
repeated Annotation type_annotation = 100;
|
||||
optional bool is_raw = 101;
|
||||
}
|
||||
|
||||
extend TypeParameter {
|
||||
repeated Annotation type_parameter_annotation = 100;
|
||||
}
|
||||
|
||||
extend Class {
|
||||
// If absent, assumed to be JvmAbi.DEFAULT_MODULE_NAME
|
||||
optional int32 class_module_name = 101 [(string_id_in_table) = true];
|
||||
|
||||
repeated Property class_local_variable = 102;
|
||||
}
|
||||
|
||||
extend Package {
|
||||
optional int32 package_module_name = 101 [(string_id_in_table) = true];
|
||||
|
||||
repeated Property package_local_variable = 102;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.serialization.jvm;
|
||||
|
||||
option java_outer_classname = "JvmPackageTable";
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
||||
message PackageTable {
|
||||
// Names of .class files for each package
|
||||
repeated PackageParts package_parts = 1;
|
||||
|
||||
// Names of .kotlin_metadata files for each package
|
||||
repeated PackageParts metadata_parts = 2;
|
||||
|
||||
// Values of @JvmPackageName annotation used in this module; can be referenced in PackageParts#class_with_jvm_package_name_package_id.
|
||||
// The names here are dot-separated, e.g. "org.foo.bar"
|
||||
repeated string jvm_package_name = 3;
|
||||
}
|
||||
|
||||
message PackageParts {
|
||||
required string package_fq_name = 1;
|
||||
|
||||
// Short names of files, without extension, present in this package. Only single file facades and multi-file _parts_ are listed here
|
||||
// (multi-file facades are not present in this list, they are defined below). Only files whose JVM package name is equal to the
|
||||
// Kotlin package name (i.e. it has not been changed with @JvmPackageName) are listed here.
|
||||
repeated string short_class_name = 2;
|
||||
|
||||
// For each name in short_class_name, index of the name of the corresponding multi-file facade class in multifile_facade_short_name + 1,
|
||||
// or 0 if the class is not a multi-file part. If there's no value in this list at some index, the value is assumed to be 0.
|
||||
// (e.g. if there are no multi-file classes in the module, this list is not going to exist at all)
|
||||
repeated int32 multifile_facade_short_name_id = 3 [packed = true];
|
||||
|
||||
// Short names of multi-file facades, used in multifile_facade_short_name_id to store the part -> facade mapping.
|
||||
repeated string multifile_facade_short_name = 4;
|
||||
|
||||
// Short names of files (single file facades), whose JVM package differs from the Kotlin package because of @JvmPackageName.
|
||||
// The JVM package name of each file is stored at the same index in class_with_jvm_package_name_package_id.
|
||||
repeated string class_with_jvm_package_name_short_name = 5;
|
||||
|
||||
// For each name in class_with_jvm_package_name_short_name, the index (into PackageTable#jvm_package_name) of the JVM package name.
|
||||
// This list should have at least one element, otherwise classes with JVM package names are going to be ignored completely.
|
||||
//
|
||||
// If there's no value in this list at some index other than 0, the value is assumed to be the same as the value of the last element
|
||||
// of this list. The intended use case for this optimization is to have just a list of a single element in the most frequent case
|
||||
// when a bunch of files from the same Kotlin package have the same JVM package name.
|
||||
repeated int32 class_with_jvm_package_name_package_id = 6 [packed = true];
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.builtins
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.scopes.GivenFunctionsMemberScope
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
class CloneableClassScope(
|
||||
storageManager: StorageManager,
|
||||
containingClass: ClassDescriptor
|
||||
) : GivenFunctionsMemberScope(storageManager, containingClass) {
|
||||
override fun computeDeclaredFunctions(): List<FunctionDescriptor> = listOf(
|
||||
SimpleFunctionDescriptorImpl.create(containingClass, Annotations.EMPTY, CLONE_NAME, DECLARATION, SourceElement.NO_SOURCE).apply {
|
||||
initialize(
|
||||
null, containingClass.thisAsReceiverParameter, emptyList(), emptyList(), containingClass.builtIns.anyType,
|
||||
Modality.OPEN, Visibilities.PROTECTED
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
companion object {
|
||||
internal val CLONE_NAME = Name.identifier("clone")
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.builtins
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.ClassDescriptorFactory
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
|
||||
class JvmBuiltInClassDescriptorFactory(
|
||||
storageManager: StorageManager,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val computeContainingDeclaration: (ModuleDescriptor) -> DeclarationDescriptor = { module ->
|
||||
module.getPackage(KOTLIN_FQ_NAME).fragments.filterIsInstance<BuiltInsPackageFragment>().first()
|
||||
}
|
||||
) : ClassDescriptorFactory {
|
||||
private val cloneable by storageManager.createLazyValue {
|
||||
ClassDescriptorImpl(
|
||||
computeContainingDeclaration(moduleDescriptor),
|
||||
CLONEABLE_NAME, Modality.ABSTRACT, ClassKind.INTERFACE, listOf(moduleDescriptor.builtIns.anyType),
|
||||
SourceElement.NO_SOURCE, /* isExternal = */ false
|
||||
).apply {
|
||||
initialize(CloneableClassScope(storageManager, this), emptySet(), null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldCreateClass(packageFqName: FqName, name: Name): Boolean =
|
||||
name == CLONEABLE_NAME && packageFqName == KOTLIN_FQ_NAME
|
||||
|
||||
override fun createClass(classId: ClassId): ClassDescriptor? =
|
||||
when (classId) {
|
||||
CLONEABLE_CLASS_ID -> cloneable
|
||||
else -> null
|
||||
}
|
||||
|
||||
override fun getAllContributedClassesIfPossible(packageFqName: FqName): Collection<ClassDescriptor> =
|
||||
when (packageFqName) {
|
||||
KOTLIN_FQ_NAME -> setOf(cloneable)
|
||||
else -> emptySet()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val KOTLIN_FQ_NAME = KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME
|
||||
private val CLONEABLE_NAME = KotlinBuiltIns.FQ_NAMES.cloneable.shortName()
|
||||
val CLONEABLE_CLASS_ID = ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.cloneable.toSafe())
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.builtins
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFactory
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.NotFoundClasses
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.AdditionalClassPartsProvider
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclarationFilter
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.serialization.deserialization.*
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
class JvmBuiltInsPackageFragmentProvider(
|
||||
storageManager: StorageManager,
|
||||
finder: KotlinClassFinder,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
notFoundClasses: NotFoundClasses,
|
||||
additionalClassPartsProvider: AdditionalClassPartsProvider,
|
||||
platformDependentDeclarationFilter: PlatformDependentDeclarationFilter
|
||||
) : AbstractDeserializedPackageFragmentProvider(storageManager, finder, moduleDescriptor) {
|
||||
init {
|
||||
components = DeserializationComponents(
|
||||
storageManager,
|
||||
moduleDescriptor,
|
||||
DeserializationConfiguration.Default, // TODO
|
||||
DeserializedClassDataFinder(this),
|
||||
AnnotationAndConstantLoaderImpl(moduleDescriptor, notFoundClasses, BuiltInSerializerProtocol),
|
||||
this,
|
||||
LocalClassifierTypeSettings.Default,
|
||||
ErrorReporter.DO_NOTHING,
|
||||
LookupTracker.DO_NOTHING,
|
||||
FlexibleTypeDeserializer.ThrowException,
|
||||
listOf(
|
||||
BuiltInFictitiousFunctionClassFactory(storageManager, moduleDescriptor),
|
||||
JvmBuiltInClassDescriptorFactory(storageManager, moduleDescriptor)
|
||||
),
|
||||
notFoundClasses,
|
||||
ContractDeserializer.DEFAULT,
|
||||
additionalClassPartsProvider, platformDependentDeclarationFilter
|
||||
)
|
||||
}
|
||||
|
||||
override fun findPackage(fqName: FqName): DeserializedPackageFragment? =
|
||||
finder.findBuiltInsData(fqName)?.let { inputStream ->
|
||||
BuiltInsPackageFragmentImpl(fqName, storageManager, moduleDescriptor, inputStream)
|
||||
}
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.load.java.lazy.NullabilityQualifierWithApplicability
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifierWithMigrationStatus
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgumentValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.utils.Jsr305State
|
||||
import org.jetbrains.kotlin.utils.ReportLevel
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
private val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname")
|
||||
private val TYPE_QUALIFIER_FQNAME = FqName("javax.annotation.meta.TypeQualifier")
|
||||
private val TYPE_QUALIFIER_DEFAULT_FQNAME = FqName("javax.annotation.meta.TypeQualifierDefault")
|
||||
|
||||
private val MIGRATION_ANNOTATION_FQNAME = FqName("kotlin.annotations.jvm.UnderMigration")
|
||||
|
||||
private val BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS = mapOf(
|
||||
FqName("javax.annotation.ParametersAreNullableByDefault") to
|
||||
NullabilityQualifierWithApplicability(
|
||||
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE),
|
||||
listOf(AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER)
|
||||
),
|
||||
FqName("javax.annotation.ParametersAreNonnullByDefault") to
|
||||
NullabilityQualifierWithApplicability(
|
||||
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL),
|
||||
listOf(AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER)
|
||||
)
|
||||
)
|
||||
|
||||
class AnnotationTypeQualifierResolver(storageManager: StorageManager, private val jsr305State: Jsr305State) {
|
||||
enum class QualifierApplicabilityType {
|
||||
METHOD_RETURN_TYPE, VALUE_PARAMETER, FIELD, TYPE_USE
|
||||
}
|
||||
|
||||
class TypeQualifierWithApplicability(
|
||||
private val typeQualifier: AnnotationDescriptor,
|
||||
private val applicability: Int
|
||||
) {
|
||||
operator fun component1() = typeQualifier
|
||||
operator fun component2() = QualifierApplicabilityType.values().filter(this::isApplicableTo)
|
||||
|
||||
private fun isApplicableTo(elementType: QualifierApplicabilityType) =
|
||||
isApplicableConsideringMask(QualifierApplicabilityType.TYPE_USE) || isApplicableConsideringMask(elementType)
|
||||
|
||||
private fun isApplicableConsideringMask(elementType: QualifierApplicabilityType) =
|
||||
(applicability and (1 shl elementType.ordinal)) != 0
|
||||
}
|
||||
|
||||
private val resolvedNicknames =
|
||||
storageManager.createMemoizedFunctionWithNullableValues(this::computeTypeQualifierNickname)
|
||||
|
||||
private fun computeTypeQualifierNickname(classDescriptor: ClassDescriptor): AnnotationDescriptor? {
|
||||
if (!classDescriptor.annotations.hasAnnotation(TYPE_QUALIFIER_NICKNAME_FQNAME)) return null
|
||||
|
||||
return classDescriptor.annotations.firstNotNullResult(this::resolveTypeQualifierAnnotation)
|
||||
}
|
||||
|
||||
private fun resolveTypeQualifierNickname(classDescriptor: ClassDescriptor): AnnotationDescriptor? {
|
||||
if (classDescriptor.kind != ClassKind.ANNOTATION_CLASS) return null
|
||||
|
||||
return resolvedNicknames(classDescriptor)
|
||||
}
|
||||
|
||||
fun resolveTypeQualifierAnnotation(annotationDescriptor: AnnotationDescriptor): AnnotationDescriptor? {
|
||||
if (jsr305State.disabled) {
|
||||
return null
|
||||
}
|
||||
|
||||
val annotationClass = annotationDescriptor.annotationClass ?: return null
|
||||
if (annotationClass.isAnnotatedWithTypeQualifier) return annotationDescriptor
|
||||
|
||||
return resolveTypeQualifierNickname(annotationClass)
|
||||
}
|
||||
|
||||
fun resolveQualifierBuiltInDefaultAnnotation(annotationDescriptor: AnnotationDescriptor): NullabilityQualifierWithApplicability? {
|
||||
if (jsr305State.disabled) {
|
||||
return null
|
||||
}
|
||||
|
||||
return BUILT_IN_TYPE_QUALIFIER_DEFAULT_ANNOTATIONS[annotationDescriptor.fqName]?.let { (qualifier, applicability) ->
|
||||
val state = resolveJsr305AnnotationState(annotationDescriptor).takeIf { it != ReportLevel.IGNORE } ?: return null
|
||||
return NullabilityQualifierWithApplicability(qualifier.copy(isForWarningOnly = state.isWarning), applicability)
|
||||
}
|
||||
}
|
||||
|
||||
fun resolveTypeQualifierDefaultAnnotation(annotationDescriptor: AnnotationDescriptor): TypeQualifierWithApplicability? {
|
||||
if (jsr305State.disabled) {
|
||||
return null
|
||||
}
|
||||
|
||||
val typeQualifierDefaultAnnotatedClass =
|
||||
annotationDescriptor.annotationClass?.takeIf { it.annotations.hasAnnotation(TYPE_QUALIFIER_DEFAULT_FQNAME) }
|
||||
?: return null
|
||||
|
||||
val elementTypesMask =
|
||||
annotationDescriptor.annotationClass!!
|
||||
.annotations.findAnnotation(TYPE_QUALIFIER_DEFAULT_FQNAME)!!
|
||||
.allValueArguments
|
||||
.flatMap { (parameter, argument) ->
|
||||
if (parameter == JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME)
|
||||
argument.mapConstantToQualifierApplicabilityTypes()
|
||||
else
|
||||
emptyList()
|
||||
}
|
||||
.fold(0) { acc: Int, applicabilityType -> acc or (1 shl applicabilityType.ordinal) }
|
||||
|
||||
val typeQualifier = typeQualifierDefaultAnnotatedClass.annotations.firstOrNull { resolveTypeQualifierAnnotation(it) != null }
|
||||
?: return null
|
||||
|
||||
return TypeQualifierWithApplicability(typeQualifier, elementTypesMask)
|
||||
}
|
||||
|
||||
fun resolveJsr305AnnotationState(annotationDescriptor: AnnotationDescriptor): ReportLevel {
|
||||
resolveJsr305CustomState(annotationDescriptor)?.let { return it }
|
||||
return jsr305State.global
|
||||
}
|
||||
|
||||
fun resolveJsr305CustomState(annotationDescriptor: AnnotationDescriptor): ReportLevel? {
|
||||
jsr305State.user[annotationDescriptor.fqName?.asString()]?.let { return it }
|
||||
return annotationDescriptor.annotationClass?.migrationAnnotationStatus()
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.migrationAnnotationStatus(): ReportLevel? {
|
||||
val stateDescriptor = annotations.findAnnotation(MIGRATION_ANNOTATION_FQNAME)?.firstArgumentValue()?.safeAs<ClassDescriptor>()
|
||||
?: return null
|
||||
|
||||
jsr305State.migration?.let { return jsr305State.migration }
|
||||
|
||||
return when (stateDescriptor.name.asString()) {
|
||||
"STRICT" -> ReportLevel.STRICT
|
||||
"WARN" -> ReportLevel.WARN
|
||||
"IGNORE" -> ReportLevel.IGNORE
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConstantValue<*>.mapConstantToQualifierApplicabilityTypes(): List<QualifierApplicabilityType> =
|
||||
when (this) {
|
||||
is ArrayValue -> value.flatMap { it.mapConstantToQualifierApplicabilityTypes() }
|
||||
is EnumValue -> listOfNotNull(
|
||||
when (value.name.identifier) {
|
||||
"METHOD" -> QualifierApplicabilityType.METHOD_RETURN_TYPE
|
||||
"FIELD" -> QualifierApplicabilityType.FIELD
|
||||
"PARAMETER" -> QualifierApplicabilityType.VALUE_PARAMETER
|
||||
"TYPE_USE" -> QualifierApplicabilityType.TYPE_USE
|
||||
else -> null
|
||||
}
|
||||
)
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
val disabled: Boolean = jsr305State.disabled
|
||||
}
|
||||
|
||||
val BUILT_IN_TYPE_QUALIFIER_FQ_NAMES = setOf(JAVAX_NONNULL_ANNOTATION, JAVAX_CHECKFORNULL_ANNOTATION)
|
||||
|
||||
private val ClassDescriptor.isAnnotatedWithTypeQualifier: Boolean
|
||||
get() = fqNameSafe in BUILT_IN_TYPE_QUALIFIER_FQ_NAMES || annotations.hasAnnotation(TYPE_QUALIFIER_FQNAME)
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition
|
||||
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition.Result
|
||||
|
||||
class BuiltinOverridabilityCondition : ExternalOverridabilityCondition {
|
||||
override fun isOverridable(
|
||||
superDescriptor: CallableDescriptor,
|
||||
subDescriptor: CallableDescriptor,
|
||||
subClassDescriptor: ClassDescriptor?
|
||||
) = Result.UNKNOWN
|
||||
|
||||
override fun getContract() = ExternalOverridabilityCondition.Contract.CONFLICTS_ONLY
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.RawSubstitution
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.RawTypeImpl
|
||||
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition
|
||||
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition.Result
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
|
||||
class ErasedOverridabilityCondition : ExternalOverridabilityCondition {
|
||||
override fun isOverridable(superDescriptor: CallableDescriptor, subDescriptor: CallableDescriptor, subClassDescriptor: ClassDescriptor?): Result {
|
||||
if (subDescriptor !is JavaMethodDescriptor || subDescriptor.typeParameters.isNotEmpty()) return Result.UNKNOWN
|
||||
|
||||
val basicOverridability = OverridingUtil.getBasicOverridabilityProblem(superDescriptor, subDescriptor)?.result
|
||||
if (basicOverridability != null) return Result.UNKNOWN
|
||||
|
||||
val signatureTypes = subDescriptor.valueParameters.asSequence().map { it.type } +
|
||||
subDescriptor.returnType!! +
|
||||
listOfNotNull(subDescriptor.extensionReceiverParameter?.type)
|
||||
|
||||
if (signatureTypes.any { it.arguments.isNotEmpty() && it.unwrap() !is RawTypeImpl }) return Result.UNKNOWN
|
||||
|
||||
var erasedSuper = superDescriptor.substitute(RawSubstitution.buildSubstitutor()) ?: return Result.UNKNOWN
|
||||
|
||||
if (erasedSuper is SimpleFunctionDescriptor && erasedSuper.typeParameters.isNotEmpty()) {
|
||||
// Only simple functions are supported now for erased overrides
|
||||
erasedSuper = erasedSuper.newCopyBuilder().setTypeParameters(emptyList()).build()!!
|
||||
}
|
||||
|
||||
val overridabilityResult =
|
||||
OverridingUtil.DEFAULT.isOverridableByWithoutExternalConditions(erasedSuper, subDescriptor, false).result
|
||||
return when (overridabilityResult) {
|
||||
OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE -> Result.OVERRIDABLE
|
||||
else -> Result.UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
override fun getContract() = ExternalOverridabilityCondition.Contract.SUCCESS_ONLY
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.builtins.KotlinBuiltIns.FQ_NAMES
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
object FakePureImplementationsProvider {
|
||||
fun getPurelyImplementedInterface(classFqName: FqName): FqName? = pureImplementations[classFqName]
|
||||
|
||||
private val pureImplementations = hashMapOf<FqName, FqName>()
|
||||
private infix fun FqName.implementedWith(implementations: List<FqName>) {
|
||||
implementations.associateTo(pureImplementations) { it to this }
|
||||
}
|
||||
|
||||
init {
|
||||
FQ_NAMES.mutableList implementedWith fqNameListOf("java.util.ArrayList", "java.util.LinkedList")
|
||||
FQ_NAMES.mutableSet implementedWith fqNameListOf("java.util.HashSet", "java.util.TreeSet", "java.util.LinkedHashSet")
|
||||
FQ_NAMES.mutableMap implementedWith fqNameListOf("java.util.HashMap", "java.util.TreeMap", "java.util.LinkedHashMap",
|
||||
"java.util.concurrent.ConcurrentHashMap", "java.util.concurrent.ConcurrentSkipListMap")
|
||||
FqName("java.util.function.Function") implementedWith fqNameListOf("java.util.function.UnaryOperator")
|
||||
FqName("java.util.function.BiFunction") implementedWith fqNameListOf("java.util.function.BinaryOperator")
|
||||
}
|
||||
|
||||
private fun fqNameListOf(vararg names: String): List<FqName> = names.map(::FqName)
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.isJavaField
|
||||
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition
|
||||
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition.Result
|
||||
|
||||
class FieldOverridabilityCondition : ExternalOverridabilityCondition {
|
||||
override fun isOverridable(superDescriptor: CallableDescriptor, subDescriptor: CallableDescriptor, subClassDescriptor: ClassDescriptor?): Result {
|
||||
if (subDescriptor !is PropertyDescriptor || superDescriptor !is PropertyDescriptor) return Result.UNKNOWN
|
||||
if (subDescriptor.name != superDescriptor.name) return Result.UNKNOWN
|
||||
|
||||
if (subDescriptor.isJavaField && superDescriptor.isJavaField) return Result.OVERRIDABLE
|
||||
if (subDescriptor.isJavaField || superDescriptor.isJavaField) return Result.INCOMPATIBLE
|
||||
|
||||
return Result.UNKNOWN
|
||||
}
|
||||
|
||||
override fun getContract() = ExternalOverridabilityCondition.Contract.BOTH
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.ReadOnly;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaPackage;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface JavaClassFinder {
|
||||
@Nullable
|
||||
JavaClass findClass(@NotNull ClassId classId);
|
||||
|
||||
@Nullable
|
||||
JavaPackage findPackage(@NotNull FqName fqName);
|
||||
|
||||
@ReadOnly
|
||||
@Nullable
|
||||
Set<String> knownClassNamesInPackage(@NotNull FqName packageFqName);
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithDifferentJvmName.sameAsRenamedInJvmBuiltin
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.sameAsBuiltinMethodWithErasedValueParameters
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmType
|
||||
import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor
|
||||
import org.jetbrains.kotlin.load.kotlin.forceSingleValueParameterBoxing
|
||||
import org.jetbrains.kotlin.load.kotlin.mapToJvmType
|
||||
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition
|
||||
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition.Result
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
|
||||
/**
|
||||
* This class contains Java-related overridability conditions that may force incompatibility
|
||||
*/
|
||||
class JavaIncompatibilityRulesOverridabilityCondition : ExternalOverridabilityCondition {
|
||||
override fun isOverridable(
|
||||
superDescriptor: CallableDescriptor,
|
||||
subDescriptor: CallableDescriptor,
|
||||
subClassDescriptor: ClassDescriptor?
|
||||
): Result {
|
||||
if (isIncompatibleInAccordanceWithBuiltInOverridabilityRules(superDescriptor, subDescriptor, subClassDescriptor)) {
|
||||
return Result.INCOMPATIBLE
|
||||
}
|
||||
|
||||
if (doesJavaOverrideHaveIncompatibleValueParameterKinds(superDescriptor, subDescriptor)) {
|
||||
return Result.INCOMPATIBLE
|
||||
}
|
||||
|
||||
return Result.UNKNOWN
|
||||
}
|
||||
|
||||
// This overridability condition checks two things:
|
||||
// 1. Method accidentally having the same signature as special builtin has does not supposed to be override for it in Java class
|
||||
// 2. In such Java class (with special signature clash) special builtin is loaded as hidden function with special signature, and
|
||||
// it should not override non-special method in further inheritance
|
||||
// See java.nio.Buffer
|
||||
private fun isIncompatibleInAccordanceWithBuiltInOverridabilityRules(
|
||||
superDescriptor: CallableDescriptor,
|
||||
subDescriptor: CallableDescriptor,
|
||||
subClassDescriptor: ClassDescriptor?
|
||||
): Boolean {
|
||||
if (superDescriptor !is CallableMemberDescriptor || subDescriptor !is FunctionDescriptor ||
|
||||
KotlinBuiltIns.isBuiltIn(subDescriptor)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (!subDescriptor.name.sameAsBuiltinMethodWithErasedValueParameters && !subDescriptor.name.sameAsRenamedInJvmBuiltin) {
|
||||
return false
|
||||
}
|
||||
|
||||
val overriddenBuiltin = superDescriptor.getOverriddenSpecialBuiltin()
|
||||
|
||||
// Checking second condition: special hidden override is not supposed to be an override to non-special irrelevant Java declaration
|
||||
val isOneOfDescriptorsHidden =
|
||||
subDescriptor.isHiddenToOvercomeSignatureClash != (superDescriptor as? FunctionDescriptor)?.isHiddenToOvercomeSignatureClash
|
||||
if (isOneOfDescriptorsHidden &&
|
||||
(overriddenBuiltin == null || !subDescriptor.isHiddenToOvercomeSignatureClash)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// If new containing class is not Java class or subDescriptor signature was artificially changed, use basic overridability rules
|
||||
if (subClassDescriptor !is JavaClassDescriptor || subDescriptor.initialSignatureDescriptor != null) {
|
||||
return false
|
||||
}
|
||||
|
||||
// If current Java class has Kotlin super class with override of overriddenBuiltin, then common overridability rules can be applied
|
||||
// because of final special bridge generated in Kotlin super class
|
||||
if (overriddenBuiltin == null || subClassDescriptor.hasRealKotlinSuperClassWithOverrideOf(overriddenBuiltin)) return false
|
||||
|
||||
// class A extends HashMap<Object, Object> {
|
||||
// void get(Object x) {}
|
||||
// }
|
||||
//
|
||||
// The problem is that when checking overridabilty of `A.get` and `HashMap.get` we fall through to here, because
|
||||
// we do not recreate a magic copy of it, because it has the same signature.
|
||||
// But it obviously that if subDescriptor and superDescriptor has the same JVM descriptor, they're one-way overridable.
|
||||
// Note that it doesn't work if special builtIn was renamed, because we do not consider renamed built-ins
|
||||
// in `computeJvmDescriptor`.
|
||||
// TODO: things get more and more complicated here, consider moving signature mapping from backend and using it here instead of all of this magic
|
||||
if (overriddenBuiltin is FunctionDescriptor && superDescriptor is FunctionDescriptor &&
|
||||
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(overriddenBuiltin) != null &&
|
||||
subDescriptor.computeJvmDescriptor(withReturnType = false) == superDescriptor.original.computeJvmDescriptor(withReturnType = false)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Here we know that something in Java with common signature is going to override some special builtin that is supposed to be
|
||||
// incompatible override
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
override fun getContract() = ExternalOverridabilityCondition.Contract.CONFLICTS_ONLY
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Checks if any pair of corresponding value parameters has different type kinds, e.g. one is primitive and another is not
|
||||
*
|
||||
* As it comes from it's name it only checks overrides in Java classes
|
||||
*/
|
||||
fun doesJavaOverrideHaveIncompatibleValueParameterKinds(
|
||||
superDescriptor: CallableDescriptor,
|
||||
subDescriptor: CallableDescriptor
|
||||
): Boolean {
|
||||
if (subDescriptor !is JavaMethodDescriptor || superDescriptor !is FunctionDescriptor) return false
|
||||
assert(subDescriptor.valueParameters.size == superDescriptor.valueParameters.size) {
|
||||
"External overridability condition with CONFLICTS_ONLY should not be run with different value parameters size"
|
||||
}
|
||||
|
||||
for ((subParameter, superParameter) in subDescriptor.original.valueParameters.zip(superDescriptor.original.valueParameters)) {
|
||||
val isSubPrimitive = mapValueParameterType(subDescriptor, subParameter) is JvmType.Primitive
|
||||
val isSuperPrimitive = mapValueParameterType(superDescriptor, superParameter) is JvmType.Primitive
|
||||
|
||||
if (isSubPrimitive != isSuperPrimitive) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun mapValueParameterType(f: FunctionDescriptor, valueParameterDescriptor: ValueParameterDescriptor) =
|
||||
if (forceSingleValueParameterBoxing(f) || isPrimitiveCompareTo(f))
|
||||
valueParameterDescriptor.type.makeNullable().mapToJvmType()
|
||||
else
|
||||
valueParameterDescriptor.type.mapToJvmType()
|
||||
|
||||
// It's useful here to suppose that 'Int.compareTo(Int)' requires boxing of it's value parameter
|
||||
// As it happens in java.lang.Integer analogue
|
||||
// It only affects additional built-ins loading (see 'testLoadBuiltIns' tests)
|
||||
private fun isPrimitiveCompareTo(f: FunctionDescriptor): Boolean {
|
||||
if (f.valueParameters.size != 1) return false
|
||||
val classDescriptor =
|
||||
f.containingDeclaration as? ClassDescriptor ?: return false
|
||||
val parameterClass =
|
||||
f.valueParameters.single().type.constructor.declarationDescriptor as? ClassDescriptor
|
||||
?: return false
|
||||
return KotlinBuiltIns.isPrimitiveClass(classDescriptor) && classDescriptor.fqNameSafe == parameterClass.fqNameSafe
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
|
||||
public class JavaVisibilities {
|
||||
private JavaVisibilities() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static final Visibility PACKAGE_VISIBILITY = new Visibility("package", false) {
|
||||
@Override
|
||||
public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
|
||||
return areInSamePackage(what, from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mustCheckInImports() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer compareTo(@NotNull Visibility visibility) {
|
||||
if (this == visibility) return 0;
|
||||
if (Visibilities.isPrivate(visibility)) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "public/*package*/";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Visibility normalize() {
|
||||
return Visibilities.PROTECTED;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public EffectiveVisibility effectiveVisibility(@NotNull DeclarationDescriptor classDescriptor, boolean checkPublishedApi) {
|
||||
return EffectiveVisibility.PackagePrivate.INSTANCE;
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
public static final Visibility PROTECTED_STATIC_VISIBILITY = new Visibility("protected_static", true) {
|
||||
@Override
|
||||
public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
|
||||
return isVisibleForProtectedAndPackage(receiver, what, from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mustCheckInImports() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "protected/*protected static*/";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Visibility normalize() {
|
||||
return Visibilities.PROTECTED;
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
public static final Visibility PROTECTED_AND_PACKAGE = new Visibility("protected_and_package", true) {
|
||||
@Override
|
||||
public boolean isVisible(@Nullable ReceiverValue receiver, @NotNull DeclarationDescriptorWithVisibility what, @NotNull DeclarationDescriptor from) {
|
||||
return isVisibleForProtectedAndPackage(receiver, what, from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mustCheckInImports() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer compareTo(@NotNull Visibility visibility) {
|
||||
if (this == visibility) return 0;
|
||||
if (visibility == Visibilities.INTERNAL) return null;
|
||||
if (Visibilities.isPrivate(visibility)) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "protected/*protected and package*/";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Visibility normalize() {
|
||||
return Visibilities.PROTECTED;
|
||||
}
|
||||
};
|
||||
|
||||
private static boolean isVisibleForProtectedAndPackage(
|
||||
@Nullable ReceiverValue receiver,
|
||||
@NotNull DeclarationDescriptorWithVisibility what,
|
||||
@NotNull DeclarationDescriptor from
|
||||
) {
|
||||
if (areInSamePackage(DescriptorUtils.unwrapFakeOverrideToAnyDeclaration(what), from)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Visibilities.PROTECTED.isVisible(receiver, what, from);
|
||||
}
|
||||
|
||||
private static boolean areInSamePackage(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) {
|
||||
PackageFragmentDescriptor whatPackage = DescriptorUtils.getParentOfType(first, PackageFragmentDescriptor.class, false);
|
||||
PackageFragmentDescriptor fromPackage = DescriptorUtils.getParentOfType(second, PackageFragmentDescriptor.class, false);
|
||||
return fromPackage != null && whatPackage != null && whatPackage.getFqName().equals(fromPackage.getFqName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.builtins.CompanionObjectMapping;
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.CapitalizeDecapitalizeKt;
|
||||
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isClassOrEnumClass;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface;
|
||||
|
||||
public final class JvmAbi {
|
||||
public static final String DEFAULT_IMPLS_CLASS_NAME = "DefaultImpls";
|
||||
|
||||
/**
|
||||
* Warning: use DEFAULT_IMPLS_CLASS_NAME and TypeMappingConfiguration.innerClassNameFactory when possible.
|
||||
* This is false for KAPT3 mode.
|
||||
*/
|
||||
public static final String DEFAULT_IMPLS_SUFFIX = "$" + DEFAULT_IMPLS_CLASS_NAME;
|
||||
public static final String DEFAULT_IMPLS_DELEGATE_SUFFIX = "$defaultImpl";
|
||||
|
||||
public static final String DEFAULT_PARAMS_IMPL_SUFFIX = "$default";
|
||||
|
||||
private static final String GET_PREFIX = "get";
|
||||
private static final String IS_PREFIX = "is";
|
||||
private static final String SET_PREFIX = "set";
|
||||
|
||||
public static final String DELEGATED_PROPERTY_NAME_SUFFIX = "$delegate";
|
||||
public static final String DELEGATED_PROPERTIES_ARRAY_NAME = "$$delegatedProperties";
|
||||
public static final String DELEGATE_SUPER_FIELD_PREFIX = "$$delegate_";
|
||||
private static final String ANNOTATIONS_SUFFIX = "$annotations";
|
||||
private static final String ANNOTATED_PROPERTY_METHOD_NAME_SUFFIX = ANNOTATIONS_SUFFIX;
|
||||
private static final String ANNOTATED_TYPEALIAS_METHOD_NAME_SUFFIX = ANNOTATIONS_SUFFIX;
|
||||
|
||||
public static final String INSTANCE_FIELD = "INSTANCE";
|
||||
public static final String HIDDEN_INSTANCE_FIELD = "$$" + INSTANCE_FIELD;
|
||||
|
||||
public static final String DEFAULT_MODULE_NAME = "main";
|
||||
public static final ClassId REFLECTION_FACTORY_IMPL = ClassId.topLevel(new FqName("kotlin.reflect.jvm.internal.ReflectionFactoryImpl"));
|
||||
|
||||
public static final String LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT = "$i$a$";
|
||||
public static final String LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION = "$i$f$";
|
||||
|
||||
@NotNull
|
||||
public static String getSyntheticMethodNameForAnnotatedProperty(@NotNull Name propertyName) {
|
||||
return propertyName.asString() + ANNOTATED_PROPERTY_METHOD_NAME_SUFFIX;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getSyntheticMethodNameForAnnotatedTypeAlias(@NotNull Name typeAliasName) {
|
||||
return typeAliasName.asString() + ANNOTATED_TYPEALIAS_METHOD_NAME_SUFFIX;
|
||||
}
|
||||
|
||||
public static boolean isGetterName(@NotNull String name) {
|
||||
return name.startsWith(GET_PREFIX) || name.startsWith(IS_PREFIX);
|
||||
}
|
||||
|
||||
public static boolean isSetterName(@NotNull String name) {
|
||||
return name.startsWith(SET_PREFIX);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getterName(@NotNull String propertyName) {
|
||||
return startsWithIsPrefix(propertyName)
|
||||
? propertyName
|
||||
: GET_PREFIX + CapitalizeDecapitalizeKt.capitalizeAsciiOnly(propertyName);
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String setterName(@NotNull String propertyName) {
|
||||
return SET_PREFIX +
|
||||
(startsWithIsPrefix(propertyName)
|
||||
? propertyName.substring(IS_PREFIX.length())
|
||||
: CapitalizeDecapitalizeKt.capitalizeAsciiOnly(propertyName));
|
||||
}
|
||||
|
||||
public static boolean startsWithIsPrefix(String name) {
|
||||
if (!name.startsWith(IS_PREFIX)) return false;
|
||||
if (name.length() == IS_PREFIX.length()) return false;
|
||||
char c = name.charAt(IS_PREFIX.length());
|
||||
return !('a' <= c && c <= 'z');
|
||||
}
|
||||
|
||||
public static boolean isPropertyWithBackingFieldInOuterClass(@NotNull PropertyDescriptor propertyDescriptor) {
|
||||
return propertyDescriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
|
||||
isCompanionObjectWithBackingFieldsInOuter(propertyDescriptor.getContainingDeclaration());
|
||||
}
|
||||
|
||||
public static boolean isCompanionObjectWithBackingFieldsInOuter(@NotNull DeclarationDescriptor companionObject) {
|
||||
return isCompanionObject(companionObject) &&
|
||||
isClassOrEnumClass(companionObject.getContainingDeclaration()) &&
|
||||
!isMappedIntrinsicCompanionObject((ClassDescriptor) companionObject);
|
||||
}
|
||||
|
||||
public static boolean isMappedIntrinsicCompanionObject(@NotNull ClassDescriptor companionObject) {
|
||||
return CompanionObjectMapping.INSTANCE.isMappedIntrinsicCompanionObject(companionObject);
|
||||
}
|
||||
|
||||
public static boolean isCompanionObjectInInterfaceNotIntrinsic(@NotNull DeclarationDescriptor companionObject) {
|
||||
return isCompanionObject(companionObject) &&
|
||||
isInterface(companionObject.getContainingDeclaration()) &&
|
||||
!isMappedIntrinsicCompanionObject((ClassDescriptor) companionObject);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
|
||||
|
||||
@SuppressWarnings("PointlessBitwiseExpression")
|
||||
public final class JvmAnnotationNames {
|
||||
public static final FqName METADATA_FQ_NAME = new FqName("kotlin.Metadata");
|
||||
public static final String METADATA_DESC = "L" + JvmClassName.byFqNameWithoutInnerClasses(METADATA_FQ_NAME).getInternalName() + ";";
|
||||
|
||||
public static final String METADATA_VERSION_FIELD_NAME = "mv";
|
||||
public static final String BYTECODE_VERSION_FIELD_NAME = "bv";
|
||||
public static final String KIND_FIELD_NAME = "k";
|
||||
public static final String METADATA_DATA_FIELD_NAME = "d1";
|
||||
public static final String METADATA_STRINGS_FIELD_NAME = "d2";
|
||||
public static final String METADATA_EXTRA_STRING_FIELD_NAME = "xs";
|
||||
public static final String METADATA_PACKAGE_NAME_FIELD_NAME = "pn";
|
||||
public static final String METADATA_MULTIFILE_CLASS_NAME_FIELD_NAME = METADATA_EXTRA_STRING_FIELD_NAME;
|
||||
public static final String METADATA_EXTRA_INT_FIELD_NAME = "xi";
|
||||
|
||||
public static final int METADATA_MULTIFILE_PARTS_INHERIT_FLAG = 1 << 0;
|
||||
public static final int METADATA_PRE_RELEASE_FLAG = 1 << 1;
|
||||
public static final int METADATA_SCRIPT_FLAG = 1 << 2;
|
||||
|
||||
public static final Name DEFAULT_ANNOTATION_MEMBER_NAME = Name.identifier("value");
|
||||
|
||||
public static final FqName JETBRAINS_NOT_NULL_ANNOTATION = new FqName("org.jetbrains.annotations.NotNull");
|
||||
public static final FqName JETBRAINS_NULLABLE_ANNOTATION = new FqName("org.jetbrains.annotations.Nullable");
|
||||
public static final FqName JETBRAINS_MUTABLE_ANNOTATION = new FqName("org.jetbrains.annotations.Mutable");
|
||||
public static final FqName JETBRAINS_READONLY_ANNOTATION = new FqName("org.jetbrains.annotations.ReadOnly");
|
||||
|
||||
public static final FqName PURELY_IMPLEMENTS_ANNOTATION = new FqName("kotlin.jvm.PurelyImplements");
|
||||
|
||||
// Just for internal use: there is no such real classes in bytecode
|
||||
public static final FqName ENHANCED_NULLABILITY_ANNOTATION = new FqName("kotlin.jvm.internal.EnhancedNullability");
|
||||
public static final FqName ENHANCED_MUTABILITY_ANNOTATION = new FqName("kotlin.jvm.internal.EnhancedMutability");
|
||||
|
||||
public static final FqName PARAMETER_NAME_FQ_NAME = new FqName("kotlin.annotations.jvm.internal.ParameterName");
|
||||
public static final FqName DEFAULT_VALUE_FQ_NAME = new FqName("kotlin.annotations.jvm.internal.DefaultValue");
|
||||
public static final FqName DEFAULT_NULL_FQ_NAME = new FqName("kotlin.annotations.jvm.internal.DefaultNull");
|
||||
|
||||
private JvmAnnotationNames() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.name.FqName
|
||||
|
||||
val NULLABLE_ANNOTATIONS = listOf(
|
||||
JvmAnnotationNames.JETBRAINS_NULLABLE_ANNOTATION,
|
||||
FqName("android.support.annotation.Nullable"),
|
||||
FqName("com.android.annotations.Nullable"),
|
||||
FqName("org.eclipse.jdt.annotation.Nullable"),
|
||||
FqName("org.checkerframework.checker.nullness.qual.Nullable"),
|
||||
FqName("javax.annotation.Nullable"),
|
||||
FqName("javax.annotation.CheckForNull"),
|
||||
FqName("edu.umd.cs.findbugs.annotations.CheckForNull"),
|
||||
FqName("edu.umd.cs.findbugs.annotations.Nullable"),
|
||||
FqName("edu.umd.cs.findbugs.annotations.PossiblyNull"),
|
||||
FqName("io.reactivex.annotations.Nullable")
|
||||
)
|
||||
|
||||
val JAVAX_NONNULL_ANNOTATION = FqName("javax.annotation.Nonnull")
|
||||
val JAVAX_CHECKFORNULL_ANNOTATION = FqName("javax.annotation.CheckForNull")
|
||||
|
||||
val NOT_NULL_ANNOTATIONS = listOf(
|
||||
JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION,
|
||||
FqName("edu.umd.cs.findbugs.annotations.NonNull"),
|
||||
FqName("android.support.annotation.NonNull"),
|
||||
FqName("com.android.annotations.NonNull"),
|
||||
FqName("org.eclipse.jdt.annotation.NonNull"),
|
||||
FqName("org.checkerframework.checker.nullness.qual.NonNull"),
|
||||
FqName("lombok.NonNull"),
|
||||
FqName("io.reactivex.annotations.NonNull")
|
||||
)
|
||||
|
||||
val READ_ONLY_ANNOTATIONS = listOf(
|
||||
JvmAnnotationNames.JETBRAINS_READONLY_ANNOTATION
|
||||
)
|
||||
|
||||
val MUTABLE_ANNOTATIONS = listOf(
|
||||
JvmAnnotationNames.JETBRAINS_MUTABLE_ANNOTATION
|
||||
)
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.serialization.deserialization.BinaryVersion
|
||||
|
||||
/**
|
||||
* The version of conventions used in bytecode of generated .class files, such as default method naming & signatures,
|
||||
* internal member name mangling specifics, property getter/setter names, etc.
|
||||
*/
|
||||
class JvmBytecodeBinaryVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
|
||||
override fun isCompatible() = this.isCompatibleTo(INSTANCE)
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val INSTANCE = JvmBytecodeBinaryVersion(1, 0, 2)
|
||||
|
||||
@JvmField
|
||||
val INVALID_VERSION = JvmBytecodeBinaryVersion()
|
||||
}
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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.components;
|
||||
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.load.java.structure.*;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.resolve.NonReportingOverrideStrategy;
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public final class DescriptorResolverUtils {
|
||||
private DescriptorResolverUtils() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <D extends CallableMemberDescriptor> Collection<D> resolveOverridesForNonStaticMembers(
|
||||
@NotNull Name name, @NotNull Collection<D> membersFromSupertypes, @NotNull Collection<D> membersFromCurrent,
|
||||
@NotNull ClassDescriptor classDescriptor, @NotNull ErrorReporter errorReporter
|
||||
) {
|
||||
return resolveOverrides(name, membersFromSupertypes, membersFromCurrent, classDescriptor, errorReporter, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <D extends CallableMemberDescriptor> Collection<D> resolveOverridesForStaticMembers(
|
||||
@NotNull Name name, @NotNull Collection<D> membersFromSupertypes, @NotNull Collection<D> membersFromCurrent,
|
||||
@NotNull ClassDescriptor classDescriptor, @NotNull ErrorReporter errorReporter
|
||||
) {
|
||||
return resolveOverrides(name, membersFromSupertypes, membersFromCurrent, classDescriptor, errorReporter, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <D extends CallableMemberDescriptor> Collection<D> resolveOverrides(
|
||||
@NotNull Name name,
|
||||
@NotNull Collection<D> membersFromSupertypes,
|
||||
@NotNull Collection<D> membersFromCurrent,
|
||||
@NotNull ClassDescriptor classDescriptor,
|
||||
@NotNull final ErrorReporter errorReporter,
|
||||
final boolean isStaticContext
|
||||
) {
|
||||
final Set<D> result = new LinkedHashSet<D>();
|
||||
|
||||
OverridingUtil.generateOverridesInFunctionGroup(
|
||||
name, membersFromSupertypes, membersFromCurrent, classDescriptor,
|
||||
new NonReportingOverrideStrategy() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addFakeOverride(@NotNull CallableMemberDescriptor fakeOverride) {
|
||||
OverridingUtil.resolveUnknownVisibilityForMember(fakeOverride, new Function1<CallableMemberDescriptor, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(@NotNull CallableMemberDescriptor descriptor) {
|
||||
errorReporter.reportCannotInferVisibility(descriptor);
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
});
|
||||
result.add((D) fakeOverride);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent) {
|
||||
// nop
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOverriddenDescriptors(
|
||||
@NotNull CallableMemberDescriptor member, @NotNull Collection<? extends CallableMemberDescriptor> overridden
|
||||
) {
|
||||
// do not set overridden descriptors for declared static fields and methods from java
|
||||
if (isStaticContext && member.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||
return;
|
||||
}
|
||||
super.setOverriddenDescriptors(member, overridden);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ValueParameterDescriptor getAnnotationParameterByName(@NotNull Name name, @NotNull ClassDescriptor annotationClass) {
|
||||
Collection<ClassConstructorDescriptor> constructors = annotationClass.getConstructors();
|
||||
if (constructors.size() != 1) return null;
|
||||
|
||||
for (ValueParameterDescriptor parameter : constructors.iterator().next().getValueParameters()) {
|
||||
if (parameter.getName().equals(name)) {
|
||||
return parameter;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isObjectMethodInInterface(@NotNull JavaMember member) {
|
||||
return member.getContainingClass().isInterface() && member instanceof JavaMethod && isObjectMethod((JavaMethod) member);
|
||||
}
|
||||
|
||||
public static boolean isObjectMethod(@NotNull JavaMethod method) {
|
||||
String name = method.getName().asString();
|
||||
if (name.equals("toString") || name.equals("hashCode")) {
|
||||
return method.getValueParameters().isEmpty();
|
||||
}
|
||||
else if (name.equals("equals")) {
|
||||
return isMethodWithOneParameterWithFqName(method, "java.lang.Object");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isMethodWithOneParameterWithFqName(@NotNull JavaMethod method, @NotNull String fqName) {
|
||||
List<JavaValueParameter> parameters = method.getValueParameters();
|
||||
if (parameters.size() == 1) {
|
||||
JavaType type = parameters.get(0).getType();
|
||||
if (type instanceof JavaClassifierType) {
|
||||
JavaClassifier classifier = ((JavaClassifierType) type).getClassifier();
|
||||
if (classifier instanceof JavaClass) {
|
||||
FqName classFqName = ((JavaClass) classifier).getFqName();
|
||||
return classFqName != null && classFqName.asString().equals(fqName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+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.components;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationOwner;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
|
||||
public interface ExternalAnnotationResolver {
|
||||
ExternalAnnotationResolver EMPTY = new ExternalAnnotationResolver() {
|
||||
@Nullable
|
||||
@Override
|
||||
public JavaAnnotation findExternalAnnotation(@NotNull JavaAnnotationOwner owner, @NotNull FqName fqName) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@Nullable
|
||||
JavaAnnotation findExternalAnnotation(@NotNull JavaAnnotationOwner owner, @NotNull FqName fqName);
|
||||
}
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* 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.components
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaAnnotationDescriptor
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
|
||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
import java.lang.annotation.Documented
|
||||
import java.lang.annotation.Retention
|
||||
import java.lang.annotation.Target
|
||||
import java.util.*
|
||||
|
||||
object JavaAnnotationMapper {
|
||||
|
||||
private val JAVA_TARGET_FQ_NAME = FqName(Target::class.java.canonicalName)
|
||||
private val JAVA_RETENTION_FQ_NAME = FqName(Retention::class.java.canonicalName)
|
||||
private val JAVA_DEPRECATED_FQ_NAME = FqName(java.lang.Deprecated::class.java.canonicalName)
|
||||
private val JAVA_DOCUMENTED_FQ_NAME = FqName(Documented::class.java.canonicalName)
|
||||
// Java8-specific thing
|
||||
private val JAVA_REPEATABLE_FQ_NAME = FqName("java.lang.annotation.Repeatable")
|
||||
|
||||
internal val DEPRECATED_ANNOTATION_MESSAGE = Name.identifier("message")
|
||||
internal val TARGET_ANNOTATION_ALLOWED_TARGETS = Name.identifier("allowedTargets")
|
||||
internal val RETENTION_ANNOTATION_VALUE = Name.identifier("value")
|
||||
|
||||
fun mapOrResolveJavaAnnotation(annotation: JavaAnnotation, c: LazyJavaResolverContext): AnnotationDescriptor? =
|
||||
when (annotation.classId) {
|
||||
ClassId.topLevel(JAVA_TARGET_FQ_NAME) -> JavaTargetAnnotationDescriptor(annotation, c)
|
||||
ClassId.topLevel(JAVA_RETENTION_FQ_NAME) -> JavaRetentionAnnotationDescriptor(annotation, c)
|
||||
ClassId.topLevel(JAVA_REPEATABLE_FQ_NAME) -> JavaAnnotationDescriptor(c, annotation, KotlinBuiltIns.FQ_NAMES.repeatable)
|
||||
ClassId.topLevel(JAVA_DOCUMENTED_FQ_NAME) -> JavaAnnotationDescriptor(c, annotation, KotlinBuiltIns.FQ_NAMES.mustBeDocumented)
|
||||
ClassId.topLevel(JAVA_DEPRECATED_FQ_NAME) -> null
|
||||
else -> LazyJavaAnnotationDescriptor(c, annotation)
|
||||
}
|
||||
|
||||
fun findMappedJavaAnnotation(
|
||||
kotlinName: FqName,
|
||||
annotationOwner: JavaAnnotationOwner,
|
||||
c: LazyJavaResolverContext
|
||||
): AnnotationDescriptor? {
|
||||
if (kotlinName == KotlinBuiltIns.FQ_NAMES.deprecated) {
|
||||
val javaAnnotation = annotationOwner.findAnnotation(JAVA_DEPRECATED_FQ_NAME)
|
||||
if (javaAnnotation != null || annotationOwner.isDeprecatedInJavaDoc) {
|
||||
return JavaDeprecatedAnnotationDescriptor(javaAnnotation, c)
|
||||
}
|
||||
}
|
||||
return kotlinToJavaNameMap[kotlinName]?.let {
|
||||
annotationOwner.findAnnotation(it)?.let {
|
||||
mapOrResolveJavaAnnotation(it, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// kotlin.annotation.annotation is treated separately
|
||||
private val kotlinToJavaNameMap: Map<FqName, FqName> =
|
||||
mapOf(KotlinBuiltIns.FQ_NAMES.target to JAVA_TARGET_FQ_NAME,
|
||||
KotlinBuiltIns.FQ_NAMES.retention to JAVA_RETENTION_FQ_NAME,
|
||||
KotlinBuiltIns.FQ_NAMES.repeatable to JAVA_REPEATABLE_FQ_NAME,
|
||||
KotlinBuiltIns.FQ_NAMES.mustBeDocumented to JAVA_DOCUMENTED_FQ_NAME)
|
||||
|
||||
val javaToKotlinNameMap: Map<FqName, FqName> =
|
||||
mapOf(JAVA_TARGET_FQ_NAME to KotlinBuiltIns.FQ_NAMES.target,
|
||||
JAVA_RETENTION_FQ_NAME to KotlinBuiltIns.FQ_NAMES.retention,
|
||||
JAVA_DEPRECATED_FQ_NAME to KotlinBuiltIns.FQ_NAMES.deprecated,
|
||||
JAVA_REPEATABLE_FQ_NAME to KotlinBuiltIns.FQ_NAMES.repeatable,
|
||||
JAVA_DOCUMENTED_FQ_NAME to KotlinBuiltIns.FQ_NAMES.mustBeDocumented)
|
||||
}
|
||||
|
||||
open class JavaAnnotationDescriptor(
|
||||
c: LazyJavaResolverContext,
|
||||
annotation: JavaAnnotation?,
|
||||
override val fqName: FqName
|
||||
): AnnotationDescriptor {
|
||||
override val source: SourceElement = annotation?.let { c.components.sourceElementFactory.source(it) } ?: SourceElement.NO_SOURCE
|
||||
|
||||
override val type: SimpleType by c.storageManager.createLazyValue { c.module.builtIns.getBuiltInClassByFqName(fqName).defaultType }
|
||||
|
||||
protected val firstArgument: JavaAnnotationArgument? = annotation?.arguments?.firstOrNull()
|
||||
|
||||
override val allValueArguments: Map<Name, ConstantValue<*>> get() = emptyMap()
|
||||
}
|
||||
|
||||
class JavaDeprecatedAnnotationDescriptor(
|
||||
annotation: JavaAnnotation?,
|
||||
c: LazyJavaResolverContext
|
||||
): JavaAnnotationDescriptor(c, annotation, KotlinBuiltIns.FQ_NAMES.deprecated) {
|
||||
override val allValueArguments: Map<Name, ConstantValue<*>> by c.storageManager.createLazyValue {
|
||||
mapOf(JavaAnnotationMapper.DEPRECATED_ANNOTATION_MESSAGE to
|
||||
ConstantValueFactory(c.module.builtIns).createStringValue("Deprecated in Java"))
|
||||
}
|
||||
}
|
||||
|
||||
class JavaTargetAnnotationDescriptor(
|
||||
annotation: JavaAnnotation,
|
||||
c: LazyJavaResolverContext
|
||||
): JavaAnnotationDescriptor(c, annotation, KotlinBuiltIns.FQ_NAMES.target) {
|
||||
override val allValueArguments by c.storageManager.createLazyValue {
|
||||
val targetArgument = when (firstArgument) {
|
||||
is JavaArrayAnnotationArgument -> JavaAnnotationTargetMapper.mapJavaTargetArguments(firstArgument.getElements(), c.module.builtIns)
|
||||
is JavaEnumValueAnnotationArgument -> JavaAnnotationTargetMapper.mapJavaTargetArguments(listOf(firstArgument), c.module.builtIns)
|
||||
else -> null
|
||||
}
|
||||
targetArgument?.let { mapOf(JavaAnnotationMapper.TARGET_ANNOTATION_ALLOWED_TARGETS to it) }.orEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
class JavaRetentionAnnotationDescriptor(
|
||||
annotation: JavaAnnotation,
|
||||
c: LazyJavaResolverContext
|
||||
): JavaAnnotationDescriptor(c, annotation, KotlinBuiltIns.FQ_NAMES.retention) {
|
||||
override val allValueArguments by c.storageManager.createLazyValue {
|
||||
val retentionArgument = JavaAnnotationTargetMapper.mapJavaRetentionArgument(firstArgument, c.module.builtIns)
|
||||
retentionArgument?.let { mapOf(JavaAnnotationMapper.RETENTION_ANNOTATION_VALUE to it) }.orEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
object JavaAnnotationTargetMapper {
|
||||
private val targetNameLists = mapOf("PACKAGE" to EnumSet.noneOf(KotlinTarget::class.java),
|
||||
"TYPE" to EnumSet.of(KotlinTarget.CLASS, KotlinTarget.FILE),
|
||||
"ANNOTATION_TYPE" to EnumSet.of(KotlinTarget.ANNOTATION_CLASS),
|
||||
"TYPE_PARAMETER" to EnumSet.of(KotlinTarget.TYPE_PARAMETER),
|
||||
"FIELD" to EnumSet.of(KotlinTarget.FIELD),
|
||||
"LOCAL_VARIABLE" to EnumSet.of(KotlinTarget.LOCAL_VARIABLE),
|
||||
"PARAMETER" to EnumSet.of(KotlinTarget.VALUE_PARAMETER),
|
||||
"CONSTRUCTOR" to EnumSet.of(KotlinTarget.CONSTRUCTOR),
|
||||
"METHOD" to EnumSet.of(KotlinTarget.FUNCTION,
|
||||
KotlinTarget.PROPERTY_GETTER,
|
||||
KotlinTarget.PROPERTY_SETTER),
|
||||
"TYPE_USE" to EnumSet.of(KotlinTarget.TYPE)
|
||||
)
|
||||
|
||||
fun mapJavaTargetArgumentByName(argumentName: String?): Set<KotlinTarget> = targetNameLists[argumentName] ?: emptySet()
|
||||
|
||||
internal fun mapJavaTargetArguments(arguments: List<JavaAnnotationArgument>, builtIns: KotlinBuiltIns): ConstantValue<*> {
|
||||
// Map arguments: java.lang.annotation.Target -> kotlin.annotation.Target
|
||||
val kotlinTargets = arguments.filterIsInstance<JavaEnumValueAnnotationArgument>()
|
||||
.flatMap { mapJavaTargetArgumentByName(it.resolve()?.name?.asString()) }
|
||||
.mapNotNull { builtIns.getAnnotationTargetEnumEntry(it) }
|
||||
.map(::EnumValue)
|
||||
val parameterDescriptor = DescriptorResolverUtils.getAnnotationParameterByName(
|
||||
JavaAnnotationMapper.TARGET_ANNOTATION_ALLOWED_TARGETS,
|
||||
builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.target)
|
||||
)
|
||||
return ArrayValue(kotlinTargets, parameterDescriptor?.type ?: ErrorUtils.createErrorType("Error: AnnotationTarget[]"), builtIns)
|
||||
}
|
||||
|
||||
private val retentionNameList = mapOf(
|
||||
"RUNTIME" to KotlinRetention.RUNTIME,
|
||||
"CLASS" to KotlinRetention.BINARY,
|
||||
"SOURCE" to KotlinRetention.SOURCE
|
||||
)
|
||||
|
||||
internal fun mapJavaRetentionArgument(element: JavaAnnotationArgument?, builtIns: KotlinBuiltIns): ConstantValue<*>? {
|
||||
// Map argument: java.lang.annotation.Retention -> kotlin.annotation.annotation
|
||||
return (element as? JavaEnumValueAnnotationArgument)?.let {
|
||||
retentionNameList[it.resolve()?.name?.asString()]?.let {
|
||||
builtIns.getAnnotationRetentionEnumEntry(it)?.let(::EnumValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.components
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaField
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
|
||||
interface JavaPropertyInitializerEvaluator {
|
||||
fun getInitializerConstant(field: JavaField, descriptor: PropertyDescriptor): ConstantValue<*>?
|
||||
|
||||
object DoNothing : JavaPropertyInitializerEvaluator {
|
||||
override fun getInitializerConstant(field: JavaField, descriptor: PropertyDescriptor) = null
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.components;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaElement;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaField;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
|
||||
public interface JavaResolverCache {
|
||||
JavaResolverCache EMPTY = new JavaResolverCache() {
|
||||
@Nullable
|
||||
@Override
|
||||
public ClassDescriptor getClassResolvedFromSource(@NotNull FqName fqName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordMethod(@NotNull JavaMethod method, @NotNull SimpleFunctionDescriptor descriptor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordConstructor(@NotNull JavaElement element, @NotNull ConstructorDescriptor descriptor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordField(@NotNull JavaField field, @NotNull PropertyDescriptor descriptor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordClass(@NotNull JavaClass javaClass, @NotNull ClassDescriptor descriptor) {
|
||||
}
|
||||
};
|
||||
|
||||
@Nullable
|
||||
ClassDescriptor getClassResolvedFromSource(@NotNull FqName fqName);
|
||||
|
||||
void recordMethod(@NotNull JavaMethod method, @NotNull SimpleFunctionDescriptor descriptor);
|
||||
|
||||
void recordConstructor(@NotNull JavaElement element, @NotNull ConstructorDescriptor descriptor);
|
||||
|
||||
void recordField(@NotNull JavaField field, @NotNull PropertyDescriptor descriptor);
|
||||
|
||||
void recordClass(@NotNull JavaClass javaClass, @NotNull ClassDescriptor descriptor);
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.components
|
||||
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
|
||||
interface SamConversionResolver {
|
||||
object Empty : SamConversionResolver {
|
||||
override fun resolveFunctionTypeIfSamInterface(classDescriptor: JavaClassDescriptor): SimpleType? = null
|
||||
}
|
||||
|
||||
fun resolveFunctionTypeIfSamInterface(classDescriptor: JavaClassDescriptor): SimpleType?
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.components;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public interface SignaturePropagator {
|
||||
SignaturePropagator DO_NOTHING = new SignaturePropagator() {
|
||||
@NotNull
|
||||
@Override
|
||||
public PropagatedSignature resolvePropagatedSignature(
|
||||
@NotNull JavaMethod method,
|
||||
@NotNull ClassDescriptor owner,
|
||||
@NotNull KotlinType returnType,
|
||||
@Nullable KotlinType receiverType,
|
||||
@NotNull List<ValueParameterDescriptor> valueParameters,
|
||||
@NotNull List<TypeParameterDescriptor> typeParameters
|
||||
) {
|
||||
return new PropagatedSignature(
|
||||
returnType, receiverType, valueParameters, typeParameters, Collections.<String>emptyList(), false
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportSignatureErrors(@NotNull CallableMemberDescriptor descriptor, @NotNull List<String> signatureErrors) {
|
||||
throw new UnsupportedOperationException("Should not be called");
|
||||
}
|
||||
};
|
||||
|
||||
class PropagatedSignature {
|
||||
private final KotlinType returnType;
|
||||
private final KotlinType receiverType;
|
||||
private final List<ValueParameterDescriptor> valueParameters;
|
||||
private final List<TypeParameterDescriptor> typeParameters;
|
||||
private final List<String> signatureErrors;
|
||||
private final boolean hasStableParameterNames;
|
||||
|
||||
public PropagatedSignature(
|
||||
@NotNull KotlinType returnType,
|
||||
@Nullable KotlinType receiverType,
|
||||
@NotNull List<ValueParameterDescriptor> valueParameters,
|
||||
@NotNull List<TypeParameterDescriptor> typeParameters,
|
||||
@NotNull List<String> signatureErrors,
|
||||
boolean hasStableParameterNames
|
||||
) {
|
||||
this.returnType = returnType;
|
||||
this.receiverType = receiverType;
|
||||
this.valueParameters = valueParameters;
|
||||
this.typeParameters = typeParameters;
|
||||
this.signatureErrors = signatureErrors;
|
||||
this.hasStableParameterNames = hasStableParameterNames;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public KotlinType getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public KotlinType getReceiverType() {
|
||||
return receiverType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<ValueParameterDescriptor> getValueParameters() {
|
||||
return valueParameters;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<TypeParameterDescriptor> getTypeParameters() {
|
||||
return typeParameters;
|
||||
}
|
||||
|
||||
public boolean hasStableParameterNames() {
|
||||
return hasStableParameterNames;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getErrors() {
|
||||
return signatureErrors;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
PropagatedSignature resolvePropagatedSignature(
|
||||
@NotNull JavaMethod method,
|
||||
@NotNull ClassDescriptor owner,
|
||||
@NotNull KotlinType returnType,
|
||||
@Nullable KotlinType receiverType,
|
||||
@NotNull List<ValueParameterDescriptor> valueParameters,
|
||||
@NotNull List<TypeParameterDescriptor> typeParameters
|
||||
);
|
||||
|
||||
void reportSignatureErrors(@NotNull CallableMemberDescriptor descriptor, @NotNull List<String> signatureErrors);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.components;
|
||||
|
||||
/**
|
||||
* We convert Java types differently, depending on where they occur in the Java code
|
||||
* This enum encodes the kinds of occurrences
|
||||
*/
|
||||
public enum TypeUsage {
|
||||
SUPERTYPE,
|
||||
COMMON
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface JavaCallableMemberDescriptor extends CallableMemberDescriptor {
|
||||
@NotNull
|
||||
JavaCallableMemberDescriptor enhance(
|
||||
@Nullable KotlinType enhancedReceiverType,
|
||||
@NotNull List<ValueParameterData> enhancedValueParametersData,
|
||||
@NotNull KotlinType enhancedReturnType
|
||||
);
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JavaClassConstructorDescriptor extends ClassConstructorDescriptorImpl implements JavaCallableMemberDescriptor {
|
||||
private Boolean hasStableParameterNames = null;
|
||||
private Boolean hasSynthesizedParameterNames = null;
|
||||
|
||||
protected JavaClassConstructorDescriptor(
|
||||
@NotNull ClassDescriptor containingDeclaration,
|
||||
@Nullable JavaClassConstructorDescriptor original,
|
||||
@NotNull Annotations annotations,
|
||||
boolean isPrimary,
|
||||
@NotNull Kind kind,
|
||||
@NotNull SourceElement source
|
||||
) {
|
||||
super(containingDeclaration, original, annotations, isPrimary, kind, source);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JavaClassConstructorDescriptor createJavaConstructor(
|
||||
@NotNull ClassDescriptor containingDeclaration,
|
||||
@NotNull Annotations annotations,
|
||||
boolean isPrimary,
|
||||
@NotNull SourceElement source
|
||||
) {
|
||||
return new JavaClassConstructorDescriptor(containingDeclaration, null, annotations, isPrimary, Kind.DECLARATION, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableParameterNames() {
|
||||
assert hasStableParameterNames != null : "hasStableParameterNames was not set: " + this;
|
||||
return hasStableParameterNames;
|
||||
}
|
||||
|
||||
public void setHasStableParameterNames(boolean hasStableParameterNames) {
|
||||
this.hasStableParameterNames = hasStableParameterNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSynthesizedParameterNames() {
|
||||
assert hasSynthesizedParameterNames != null : "hasSynthesizedParameterNames was not set: " + this;
|
||||
return hasSynthesizedParameterNames;
|
||||
}
|
||||
|
||||
public void setHasSynthesizedParameterNames(boolean hasSynthesizedParameterNames) {
|
||||
this.hasSynthesizedParameterNames = hasSynthesizedParameterNames;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected JavaClassConstructorDescriptor createSubstitutedCopy(
|
||||
@NotNull DeclarationDescriptor newOwner,
|
||||
@Nullable FunctionDescriptor original,
|
||||
@NotNull Kind kind,
|
||||
@Nullable Name newName,
|
||||
@NotNull Annotations annotations,
|
||||
@NotNull SourceElement source
|
||||
) {
|
||||
if (kind != Kind.DECLARATION && kind != Kind.SYNTHESIZED) {
|
||||
throw new IllegalStateException(
|
||||
"Attempt at creating a constructor that is not a declaration: \n" +
|
||||
"copy from: " + this + "\n" +
|
||||
"newOwner: " + newOwner + "\n" +
|
||||
"kind: " + kind
|
||||
);
|
||||
}
|
||||
|
||||
assert newName == null : "Attempt to rename constructor: " + this;
|
||||
|
||||
JavaClassConstructorDescriptor result =
|
||||
createDescriptor((ClassDescriptor) newOwner, (JavaClassConstructorDescriptor) original, kind, source, annotations);
|
||||
result.setHasStableParameterNames(hasStableParameterNames());
|
||||
result.setHasSynthesizedParameterNames(hasSynthesizedParameterNames());
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected JavaClassConstructorDescriptor createDescriptor(
|
||||
@NotNull ClassDescriptor newOwner,
|
||||
@Nullable JavaClassConstructorDescriptor original,
|
||||
@NotNull Kind kind,
|
||||
@NotNull SourceElement sourceElement,
|
||||
@NotNull Annotations annotations
|
||||
) {
|
||||
return new JavaClassConstructorDescriptor(
|
||||
newOwner, original, annotations, isPrimary, kind,
|
||||
sourceElement
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JavaClassConstructorDescriptor enhance(
|
||||
@Nullable KotlinType enhancedReceiverType,
|
||||
@NotNull List<ValueParameterData> enhancedValueParametersData,
|
||||
@NotNull KotlinType enhancedReturnType
|
||||
) {
|
||||
JavaClassConstructorDescriptor enhanced = createSubstitutedCopy(
|
||||
getContainingDeclaration(), /* original = */ null, getKind(), null, getAnnotations(), getSource());
|
||||
// We do not use doSubstitute here as in JavaMethodDescriptor.enhance because type parameters of constructor belongs to class
|
||||
enhanced.initialize(
|
||||
enhancedReceiverType,
|
||||
getDispatchReceiverParameter(),
|
||||
getTypeParameters(),
|
||||
UtilKt.copyValueParameters(enhancedValueParametersData, getValueParameters(), enhanced),
|
||||
enhancedReturnType,
|
||||
getModality(),
|
||||
getVisibility()
|
||||
);
|
||||
|
||||
return enhanced;
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.types.SimpleType;
|
||||
|
||||
public interface JavaClassDescriptor extends ClassDescriptor {
|
||||
// Use SingleAbstractMethodUtils.getFunctionTypeForSamInterface() where possible. This is only a fallback
|
||||
@Nullable
|
||||
SimpleType getDefaultFunctionTypeForSamInterface();
|
||||
|
||||
/**
|
||||
* May return false even in case when the class is not SAM interface, but returns true only if it's definitely not a SAM.
|
||||
* But it should work much faster than the exact check.
|
||||
*/
|
||||
boolean isDefinitelyNotSamInterface();
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.util.OperatorChecks;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implements JavaCallableMemberDescriptor {
|
||||
// TODO: It's only used to retrieve annotations from the original value parameter and can be removed when
|
||||
// org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl.initialize accepts extension parameter descriptor
|
||||
// instead of type
|
||||
public static final UserDataKey<ValueParameterDescriptor> ORIGINAL_VALUE_PARAMETER_FOR_EXTENSION_RECEIVER =
|
||||
new UserDataKey<ValueParameterDescriptor>() {};
|
||||
|
||||
private enum ParameterNamesStatus {
|
||||
NON_STABLE_DECLARED(false, false),
|
||||
STABLE_DECLARED(true, false),
|
||||
NON_STABLE_SYNTHESIZED(false, true),
|
||||
STABLE_SYNTHESIZED(true, true), // TODO: this makes no sense
|
||||
;
|
||||
|
||||
public final boolean isStable;
|
||||
public final boolean isSynthesized;
|
||||
|
||||
ParameterNamesStatus(boolean isStable, boolean isSynthesized) {
|
||||
this.isStable = isStable;
|
||||
this.isSynthesized = isSynthesized;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ParameterNamesStatus get(boolean stable, boolean synthesized) {
|
||||
return stable ? (synthesized ? STABLE_SYNTHESIZED : STABLE_DECLARED) :
|
||||
(synthesized ? NON_STABLE_SYNTHESIZED : NON_STABLE_DECLARED);
|
||||
}
|
||||
}
|
||||
|
||||
private ParameterNamesStatus parameterNamesStatus = null;
|
||||
|
||||
protected JavaMethodDescriptor(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@Nullable SimpleFunctionDescriptor original,
|
||||
@NotNull Annotations annotations,
|
||||
@NotNull Name name,
|
||||
@NotNull Kind kind,
|
||||
@NotNull SourceElement source
|
||||
) {
|
||||
super(containingDeclaration, original, annotations, name, kind, source);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JavaMethodDescriptor createJavaMethod(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@NotNull Annotations annotations,
|
||||
@NotNull Name name,
|
||||
@NotNull SourceElement source
|
||||
) {
|
||||
return new JavaMethodDescriptor(containingDeclaration, null, annotations, name, Kind.DECLARATION, source);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public SimpleFunctionDescriptorImpl initialize(
|
||||
@Nullable KotlinType receiverParameterType,
|
||||
@Nullable ReceiverParameterDescriptor dispatchReceiverParameter,
|
||||
@NotNull List<? extends TypeParameterDescriptor> typeParameters,
|
||||
@NotNull List<ValueParameterDescriptor> unsubstitutedValueParameters,
|
||||
@Nullable KotlinType unsubstitutedReturnType,
|
||||
@Nullable Modality modality,
|
||||
@NotNull Visibility visibility,
|
||||
@Nullable Map<? extends UserDataKey<?>, ?> userData
|
||||
) {
|
||||
SimpleFunctionDescriptorImpl descriptor = super.initialize(
|
||||
receiverParameterType, dispatchReceiverParameter, typeParameters, unsubstitutedValueParameters,
|
||||
unsubstitutedReturnType, modality, visibility, userData);
|
||||
setOperator(OperatorChecks.INSTANCE.check(descriptor).isSuccess());
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableParameterNames() {
|
||||
assert parameterNamesStatus != null : "Parameter names status was not set: " + this;
|
||||
return parameterNamesStatus.isStable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSynthesizedParameterNames() {
|
||||
assert parameterNamesStatus != null : "Parameter names status was not set: " + this;
|
||||
return parameterNamesStatus.isSynthesized;
|
||||
}
|
||||
|
||||
public void setParameterNamesStatus(boolean hasStableParameterNames, boolean hasSynthesizedParameterNames) {
|
||||
this.parameterNamesStatus = ParameterNamesStatus.get(hasStableParameterNames, hasSynthesizedParameterNames);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected JavaMethodDescriptor createSubstitutedCopy(
|
||||
@NotNull DeclarationDescriptor newOwner,
|
||||
@Nullable FunctionDescriptor original,
|
||||
@NotNull Kind kind,
|
||||
@Nullable Name newName,
|
||||
@NotNull Annotations annotations,
|
||||
@NotNull SourceElement source
|
||||
) {
|
||||
JavaMethodDescriptor result = new JavaMethodDescriptor(
|
||||
newOwner,
|
||||
(SimpleFunctionDescriptor) original,
|
||||
annotations,
|
||||
newName != null ? newName : getName(),
|
||||
kind,
|
||||
source
|
||||
);
|
||||
result.setParameterNamesStatus(hasStableParameterNames(), hasSynthesizedParameterNames());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JavaMethodDescriptor enhance(
|
||||
@Nullable KotlinType enhancedReceiverType,
|
||||
@NotNull List<ValueParameterData> enhancedValueParametersData,
|
||||
@NotNull KotlinType enhancedReturnType
|
||||
) {
|
||||
List<ValueParameterDescriptor> enhancedValueParameters =
|
||||
UtilKt.copyValueParameters(enhancedValueParametersData, getValueParameters(), this);
|
||||
|
||||
JavaMethodDescriptor enhancedMethod =
|
||||
(JavaMethodDescriptor) newCopyBuilder()
|
||||
.setValueParameters(enhancedValueParameters)
|
||||
.setReturnType(enhancedReturnType)
|
||||
.setExtensionReceiverType(enhancedReceiverType)
|
||||
.setDropOriginalInContainingParts()
|
||||
.setPreserveSourceElement()
|
||||
.build();
|
||||
|
||||
assert enhancedMethod != null : "null after substitution while enhancing " + toString();
|
||||
return enhancedMethod;
|
||||
}
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
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.descriptors.impl.PropertySetterDescriptorImpl;
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.TypeEnhancementKt;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JavaPropertyDescriptor extends PropertyDescriptorImpl implements JavaCallableMemberDescriptor {
|
||||
private final boolean isStaticFinal;
|
||||
|
||||
private JavaPropertyDescriptor(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@NotNull Annotations annotations,
|
||||
@NotNull Modality modality,
|
||||
@NotNull Visibility visibility,
|
||||
boolean isVar,
|
||||
@NotNull Name name,
|
||||
@NotNull SourceElement source,
|
||||
@Nullable PropertyDescriptor original,
|
||||
@NotNull Kind kind,
|
||||
boolean isStaticFinal
|
||||
) {
|
||||
super(containingDeclaration, original, annotations, modality, visibility, isVar, name, kind, source,
|
||||
false, false, false, false, false, false);
|
||||
|
||||
this.isStaticFinal = isStaticFinal;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JavaPropertyDescriptor create(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@NotNull Annotations annotations,
|
||||
@NotNull Modality modality,
|
||||
@NotNull Visibility visibility,
|
||||
boolean isVar,
|
||||
@NotNull Name name,
|
||||
@NotNull SourceElement source,
|
||||
boolean isStaticFinal
|
||||
) {
|
||||
return new JavaPropertyDescriptor(
|
||||
containingDeclaration, annotations, modality, visibility, isVar, name, source, null, Kind.DECLARATION, isStaticFinal
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected PropertyDescriptorImpl createSubstitutedCopy(
|
||||
@NotNull DeclarationDescriptor newOwner,
|
||||
@NotNull Modality newModality,
|
||||
@NotNull Visibility newVisibility,
|
||||
@Nullable PropertyDescriptor original,
|
||||
@NotNull Kind kind,
|
||||
@NotNull Name newName
|
||||
) {
|
||||
return new JavaPropertyDescriptor(
|
||||
newOwner, getAnnotations(), newModality, newVisibility, isVar(), newName, SourceElement.NO_SOURCE, original,
|
||||
kind, isStaticFinal
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSynthesizedParameterNames() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JavaCallableMemberDescriptor enhance(
|
||||
@Nullable KotlinType enhancedReceiverType,
|
||||
@NotNull List<ValueParameterData> enhancedValueParametersData,
|
||||
@NotNull KotlinType enhancedReturnType
|
||||
) {
|
||||
JavaPropertyDescriptor enhanced = new JavaPropertyDescriptor(
|
||||
getContainingDeclaration(),
|
||||
getAnnotations(),
|
||||
getModality(),
|
||||
getVisibility(),
|
||||
isVar(),
|
||||
getName(),
|
||||
getSource(),
|
||||
getOriginal(),
|
||||
getKind(),
|
||||
isStaticFinal
|
||||
);
|
||||
|
||||
PropertyGetterDescriptorImpl newGetter = null;
|
||||
PropertyGetterDescriptorImpl getter = getGetter();
|
||||
if (getter != null) {
|
||||
newGetter = new PropertyGetterDescriptorImpl(
|
||||
enhanced, getter.getAnnotations(), getter.getModality(), getter.getVisibility(),
|
||||
getter.isDefault(), getter.isExternal(), getter.isInline(), getKind(), getter, getter.getSource()
|
||||
);
|
||||
newGetter.setInitialSignatureDescriptor(getter.getInitialSignatureDescriptor());
|
||||
newGetter.initialize(enhancedReturnType);
|
||||
}
|
||||
|
||||
PropertySetterDescriptorImpl newSetter = null;
|
||||
PropertySetterDescriptor setter = getSetter();
|
||||
if (setter != null) {
|
||||
newSetter = new PropertySetterDescriptorImpl(
|
||||
enhanced, setter.getAnnotations(), setter.getModality(), setter.getVisibility(),
|
||||
setter.isDefault(), setter.isExternal(), setter.isInline(), getKind(), setter, setter.getSource()
|
||||
);
|
||||
newSetter.setInitialSignatureDescriptor(newSetter.getInitialSignatureDescriptor());
|
||||
newSetter.initialize(setter.getValueParameters().get(0));
|
||||
}
|
||||
|
||||
enhanced.initialize(newGetter, newSetter);
|
||||
enhanced.setSetterProjectedOut(isSetterProjectedOut());
|
||||
if (compileTimeInitializer != null) {
|
||||
enhanced.setCompileTimeInitializer(compileTimeInitializer);
|
||||
}
|
||||
|
||||
enhanced.setOverriddenDescriptors(getOverriddenDescriptors());
|
||||
|
||||
enhanced.setType(
|
||||
enhancedReturnType,
|
||||
getTypeParameters(), // TODO
|
||||
getDispatchReceiverParameter(),
|
||||
enhancedReceiverType
|
||||
);
|
||||
return enhanced;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConst() {
|
||||
KotlinType type = getType();
|
||||
return isStaticFinal && ConstUtil.canBeUsedForConstVal(type) &&
|
||||
(!TypeEnhancementKt.hasEnhancedNullability(type) || KotlinBuiltIns.isString(type));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaStaticClassScope
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgumentValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class ValueParameterData(val type: KotlinType, val hasDefaultValue: Boolean)
|
||||
|
||||
fun copyValueParameters(
|
||||
newValueParametersTypes: Collection<ValueParameterData>,
|
||||
oldValueParameters: Collection<ValueParameterDescriptor>,
|
||||
newOwner: CallableDescriptor
|
||||
): List<ValueParameterDescriptor> {
|
||||
assert(newValueParametersTypes.size == oldValueParameters.size) {
|
||||
"Different value parameters sizes: Enhanced = ${newValueParametersTypes.size}, Old = ${oldValueParameters.size}"
|
||||
}
|
||||
|
||||
return newValueParametersTypes.zip(oldValueParameters).map { (newParameter, oldParameter) ->
|
||||
ValueParameterDescriptorImpl(
|
||||
newOwner,
|
||||
null,
|
||||
oldParameter.index,
|
||||
oldParameter.annotations,
|
||||
oldParameter.name,
|
||||
newParameter.type,
|
||||
newParameter.hasDefaultValue,
|
||||
oldParameter.isCrossinline,
|
||||
oldParameter.isNoinline,
|
||||
if (oldParameter.varargElementType != null) newOwner.module.builtIns.getArrayElementType(newParameter.type) else null,
|
||||
oldParameter.source
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun ClassDescriptor.getParentJavaStaticClassScope(): LazyJavaStaticClassScope? {
|
||||
val superClassDescriptor = getSuperClassNotAny() ?: return null
|
||||
|
||||
val staticScope = superClassDescriptor.staticScope
|
||||
|
||||
if (staticScope !is LazyJavaStaticClassScope) return superClassDescriptor.getParentJavaStaticClassScope()
|
||||
|
||||
return staticScope
|
||||
}
|
||||
|
||||
fun DeserializedMemberDescriptor.getImplClassNameForDeserialized(): JvmClassName? =
|
||||
(containerSource as? JvmPackagePartSource)?.className
|
||||
|
||||
fun DeserializedMemberDescriptor.isFromJvmPackagePart(): Boolean =
|
||||
containerSource is JvmPackagePartSource
|
||||
|
||||
fun ValueParameterDescriptor.getParameterNameAnnotation(): AnnotationDescriptor? {
|
||||
val annotation = annotations.findAnnotation(JvmAnnotationNames.PARAMETER_NAME_FQ_NAME) ?: return null
|
||||
if (annotation.firstArgumentValue()?.safeAs<String>()?.isEmpty() != false) {
|
||||
return null
|
||||
}
|
||||
|
||||
return annotation
|
||||
}
|
||||
|
||||
sealed class AnnotationDefaultValue
|
||||
class StringDefaultValue(val value: String) : AnnotationDefaultValue()
|
||||
object NullDefaultValue : AnnotationDefaultValue()
|
||||
|
||||
fun ValueParameterDescriptor.getDefaultValueFromAnnotation(): AnnotationDefaultValue? {
|
||||
annotations.findAnnotation(JvmAnnotationNames.DEFAULT_VALUE_FQ_NAME)
|
||||
?.firstArgumentValue()
|
||||
?.safeAs<String>()
|
||||
?.let { return StringDefaultValue(it) }
|
||||
|
||||
if (annotations.hasAnnotation(JvmAnnotationNames.DEFAULT_NULL_FQ_NAME)) {
|
||||
return NullDefaultValue
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.lazy
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.load.java.components.JavaAnnotationMapper
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationOwner
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
class LazyJavaAnnotations(
|
||||
private val c: LazyJavaResolverContext,
|
||||
private val annotationOwner: JavaAnnotationOwner
|
||||
) : Annotations {
|
||||
private val annotationDescriptors = c.components.storageManager.createMemoizedFunctionWithNullableValues {
|
||||
annotation: JavaAnnotation -> JavaAnnotationMapper.mapOrResolveJavaAnnotation(annotation, c)
|
||||
}
|
||||
|
||||
override fun findAnnotation(fqName: FqName) =
|
||||
annotationOwner.findAnnotation(fqName)?.let(annotationDescriptors)
|
||||
?: JavaAnnotationMapper.findMappedJavaAnnotation(fqName, annotationOwner, c)
|
||||
|
||||
override fun findExternalAnnotation(fqName: FqName) =
|
||||
c.components.externalAnnotationResolver.findExternalAnnotation(annotationOwner, fqName)?.let(annotationDescriptors)
|
||||
|
||||
override fun getUseSiteTargetedAnnotations() = emptyList<AnnotationWithTarget>()
|
||||
|
||||
override fun getAllAnnotations() = this.map { AnnotationWithTarget(it, null) }
|
||||
|
||||
override fun iterator() =
|
||||
(annotationOwner.annotations.asSequence().map(annotationDescriptors)
|
||||
+ JavaAnnotationMapper.findMappedJavaAnnotation(KotlinBuiltIns.FQ_NAMES.deprecated, annotationOwner, c)).filterNotNull().iterator()
|
||||
|
||||
override fun isEmpty() = !iterator().hasNext()
|
||||
}
|
||||
|
||||
fun LazyJavaResolverContext.resolveAnnotations(annotationsOwner: JavaAnnotationOwner): Annotations
|
||||
= LazyJavaAnnotations(this, annotationsOwner)
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.lazy
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageFragment
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.storage.MemoizedFunctionToNullable
|
||||
|
||||
class LazyJavaPackageFragmentProvider(
|
||||
components: JavaResolverComponents
|
||||
) : PackageFragmentProvider {
|
||||
|
||||
private val c = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY, lazyOf(null))
|
||||
|
||||
private val packageFragments: MemoizedFunctionToNullable<FqName, LazyJavaPackageFragment> =
|
||||
c.storageManager.createMemoizedFunctionWithNullableValues {
|
||||
fqName ->
|
||||
val jPackage = c.components.finder.findPackage(fqName)
|
||||
if (jPackage != null) {
|
||||
LazyJavaPackageFragment(c, jPackage)
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
private fun getPackageFragment(fqName: FqName) = packageFragments(fqName)
|
||||
|
||||
override fun getPackageFragments(fqName: FqName) = listOfNotNull(getPackageFragment(fqName))
|
||||
|
||||
override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean) =
|
||||
getPackageFragment(fqName)?.getSubPackageFqNames().orEmpty()
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.lazy
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
|
||||
import javax.inject.Inject
|
||||
|
||||
interface ModuleClassResolver {
|
||||
fun resolveClass(javaClass: JavaClass): ClassDescriptor?
|
||||
}
|
||||
|
||||
class SingleModuleClassResolver() : ModuleClassResolver {
|
||||
override fun resolveClass(javaClass: JavaClass): ClassDescriptor? = resolver.resolveClass(javaClass)
|
||||
|
||||
// component dependency cycle
|
||||
lateinit var resolver: JavaDescriptorResolver
|
||||
@Inject set
|
||||
}
|
||||
|
||||
class ModuleClassResolverImpl(private val descriptorResolverByJavaClass: (JavaClass) -> JavaDescriptorResolver): ModuleClassResolver {
|
||||
override fun resolveClass(javaClass: JavaClass): ClassDescriptor? = descriptorResolverByJavaClass(javaClass).resolveClass(javaClass)
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.lazy
|
||||
|
||||
//interface PackageMappingProvider {
|
||||
//
|
||||
// fun findPackageMembers(packageName: String): List<String>
|
||||
//
|
||||
// companion object {
|
||||
// val EMPTY = object : PackageMappingProvider {
|
||||
// override fun findPackageMembers(packageName: String): List<String> {
|
||||
// return emptyList()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.lazy
|
||||
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||
import org.jetbrains.kotlin.load.java.components.*
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeResolver
|
||||
import org.jetbrains.kotlin.load.java.sources.JavaSourceElementFactory
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameterListOwner
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.JavaTypeQualifiers
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifierWithMigrationStatus
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.SignatureEnhancement
|
||||
import org.jetbrains.kotlin.load.kotlin.DeserializedDescriptorResolver
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.utils.ReportLevel
|
||||
import java.util.*
|
||||
|
||||
class JavaResolverComponents(
|
||||
val storageManager: StorageManager,
|
||||
val finder: JavaClassFinder,
|
||||
val kotlinClassFinder: KotlinClassFinder,
|
||||
val deserializedDescriptorResolver: DeserializedDescriptorResolver,
|
||||
val externalAnnotationResolver: ExternalAnnotationResolver,
|
||||
val signaturePropagator: SignaturePropagator,
|
||||
val errorReporter: ErrorReporter,
|
||||
val javaResolverCache: JavaResolverCache,
|
||||
val javaPropertyInitializerEvaluator: JavaPropertyInitializerEvaluator,
|
||||
val samConversionResolver: SamConversionResolver,
|
||||
val sourceElementFactory: JavaSourceElementFactory,
|
||||
val moduleClassResolver: ModuleClassResolver,
|
||||
val packageMapper: PackagePartProvider,
|
||||
val supertypeLoopChecker: SupertypeLoopChecker,
|
||||
val lookupTracker: LookupTracker,
|
||||
val module: ModuleDescriptor,
|
||||
val reflectionTypes: ReflectionTypes,
|
||||
val annotationTypeQualifierResolver: AnnotationTypeQualifierResolver,
|
||||
val signatureEnhancement: SignatureEnhancement
|
||||
) {
|
||||
fun replace(
|
||||
javaResolverCache: JavaResolverCache = this.javaResolverCache
|
||||
) = JavaResolverComponents(
|
||||
storageManager, finder, kotlinClassFinder, deserializedDescriptorResolver,
|
||||
externalAnnotationResolver, signaturePropagator, errorReporter, javaResolverCache,
|
||||
javaPropertyInitializerEvaluator, samConversionResolver, sourceElementFactory,
|
||||
moduleClassResolver, packageMapper, supertypeLoopChecker, lookupTracker, module, reflectionTypes,
|
||||
annotationTypeQualifierResolver, signatureEnhancement
|
||||
)
|
||||
}
|
||||
|
||||
private typealias QualifierByApplicabilityType = EnumMap<AnnotationTypeQualifierResolver.QualifierApplicabilityType, NullabilityQualifierWithMigrationStatus?>
|
||||
|
||||
class JavaTypeQualifiersByElementType(
|
||||
internal val nullabilityQualifiers: QualifierByApplicabilityType
|
||||
) {
|
||||
operator fun get(
|
||||
applicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType?
|
||||
): JavaTypeQualifiers? {
|
||||
val nullabilityQualifierWithMigrationStatus = nullabilityQualifiers[applicabilityType] ?: return null
|
||||
|
||||
return JavaTypeQualifiers(
|
||||
nullabilityQualifierWithMigrationStatus.qualifier, null,
|
||||
isNotNullTypeParameter = false,
|
||||
isNullabilityQualifierForWarning = nullabilityQualifierWithMigrationStatus.isForWarningOnly
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class LazyJavaResolverContext internal constructor(
|
||||
val components: JavaResolverComponents,
|
||||
val typeParameterResolver: TypeParameterResolver,
|
||||
internal val delegateForDefaultTypeQualifiers: Lazy<JavaTypeQualifiersByElementType?>
|
||||
) {
|
||||
constructor(
|
||||
components: JavaResolverComponents,
|
||||
typeParameterResolver: TypeParameterResolver,
|
||||
typeQualifiersComputation: () -> JavaTypeQualifiersByElementType?
|
||||
) : this(components, typeParameterResolver, lazy(LazyThreadSafetyMode.NONE, typeQualifiersComputation))
|
||||
|
||||
val defaultTypeQualifiers: JavaTypeQualifiersByElementType? by delegateForDefaultTypeQualifiers
|
||||
|
||||
val typeResolver = JavaTypeResolver(this, typeParameterResolver)
|
||||
|
||||
val storageManager: StorageManager
|
||||
get() = components.storageManager
|
||||
|
||||
val module: ModuleDescriptor get() = components.module
|
||||
}
|
||||
|
||||
fun LazyJavaResolverContext.child(
|
||||
typeParameterResolver: TypeParameterResolver
|
||||
) = LazyJavaResolverContext(components, typeParameterResolver, delegateForDefaultTypeQualifiers)
|
||||
|
||||
fun LazyJavaResolverContext.computeNewDefaultTypeQualifiers(
|
||||
additionalAnnotations: Annotations
|
||||
): JavaTypeQualifiersByElementType? {
|
||||
if (components.annotationTypeQualifierResolver.disabled) return defaultTypeQualifiers
|
||||
|
||||
val nullabilityQualifiersWithApplicability =
|
||||
additionalAnnotations.mapNotNull(this::extractDefaultNullabilityQualifier)
|
||||
|
||||
if (nullabilityQualifiersWithApplicability.isEmpty()) return defaultTypeQualifiers
|
||||
|
||||
val nullabilityQualifiersByType =
|
||||
defaultTypeQualifiers?.nullabilityQualifiers?.let(::QualifierByApplicabilityType)
|
||||
?: QualifierByApplicabilityType(AnnotationTypeQualifierResolver.QualifierApplicabilityType::class.java)
|
||||
|
||||
var wasUpdate = false
|
||||
for ((nullability, applicableTo) in nullabilityQualifiersWithApplicability) {
|
||||
for (applicabilityType in applicableTo) {
|
||||
nullabilityQualifiersByType[applicabilityType] = nullability
|
||||
wasUpdate = true
|
||||
}
|
||||
}
|
||||
|
||||
return if (!wasUpdate) defaultTypeQualifiers else JavaTypeQualifiersByElementType(nullabilityQualifiersByType)
|
||||
}
|
||||
|
||||
private fun LazyJavaResolverContext.extractDefaultNullabilityQualifier(
|
||||
annotationDescriptor: AnnotationDescriptor
|
||||
): NullabilityQualifierWithApplicability? {
|
||||
val typeQualifierResolver = components.annotationTypeQualifierResolver
|
||||
typeQualifierResolver.resolveQualifierBuiltInDefaultAnnotation(annotationDescriptor)?.let { return it }
|
||||
|
||||
val (typeQualifier, applicability) =
|
||||
typeQualifierResolver.resolveTypeQualifierDefaultAnnotation(annotationDescriptor)
|
||||
?: return null
|
||||
|
||||
val jsr305State = typeQualifierResolver.resolveJsr305CustomState(annotationDescriptor)
|
||||
?: typeQualifierResolver.resolveJsr305AnnotationState(typeQualifier)
|
||||
|
||||
if (jsr305State.isIgnore) {
|
||||
return null
|
||||
}
|
||||
|
||||
val nullabilityQualifier =
|
||||
components
|
||||
.signatureEnhancement
|
||||
.extractNullability(typeQualifier)
|
||||
?.copy(isForWarningOnly = jsr305State.isWarning)
|
||||
?: return null
|
||||
|
||||
return NullabilityQualifierWithApplicability(nullabilityQualifier, applicability)
|
||||
}
|
||||
|
||||
data class NullabilityQualifierWithApplicability(
|
||||
val nullabilityQualifier: NullabilityQualifierWithMigrationStatus,
|
||||
val qualifierApplicabilityTypes: Collection<AnnotationTypeQualifierResolver.QualifierApplicabilityType>
|
||||
)
|
||||
|
||||
fun LazyJavaResolverContext.replaceComponents(
|
||||
components: JavaResolverComponents
|
||||
) = LazyJavaResolverContext(components, typeParameterResolver, delegateForDefaultTypeQualifiers)
|
||||
|
||||
private fun LazyJavaResolverContext.child(
|
||||
containingDeclaration: DeclarationDescriptor,
|
||||
typeParameterOwner: JavaTypeParameterListOwner?,
|
||||
typeParametersIndexOffset: Int = 0,
|
||||
delegateForTypeQualifiers: Lazy<JavaTypeQualifiersByElementType?>
|
||||
) = LazyJavaResolverContext(
|
||||
components,
|
||||
typeParameterOwner?.let { LazyJavaTypeParameterResolver(this, containingDeclaration, it, typeParametersIndexOffset) }
|
||||
?: typeParameterResolver,
|
||||
delegateForTypeQualifiers
|
||||
)
|
||||
|
||||
fun LazyJavaResolverContext.childForMethod(
|
||||
containingDeclaration: DeclarationDescriptor,
|
||||
typeParameterOwner: JavaTypeParameterListOwner,
|
||||
typeParametersIndexOffset: Int = 0
|
||||
) = child(containingDeclaration, typeParameterOwner, typeParametersIndexOffset, delegateForDefaultTypeQualifiers)
|
||||
|
||||
fun LazyJavaResolverContext.childForClassOrPackage(
|
||||
containingDeclaration: ClassOrPackageFragmentDescriptor,
|
||||
typeParameterOwner: JavaTypeParameterListOwner? = null,
|
||||
typeParametersIndexOffset: Int = 0
|
||||
) = child(
|
||||
containingDeclaration, typeParameterOwner, typeParametersIndexOffset,
|
||||
lazy(LazyThreadSafetyMode.NONE) { computeNewDefaultTypeQualifiers(containingDeclaration.annotations) }
|
||||
)
|
||||
|
||||
fun LazyJavaResolverContext.copyWithNewDefaultTypeQualifiers(
|
||||
additionalAnnotations: Annotations
|
||||
) = if (additionalAnnotations.isEmpty())
|
||||
this
|
||||
else
|
||||
LazyJavaResolverContext(
|
||||
components, typeParameterResolver,
|
||||
lazy(LazyThreadSafetyMode.NONE) { computeNewDefaultTypeQualifiers(additionalAnnotations) }
|
||||
)
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.lazy.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaField
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMember
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
interface DeclaredMemberIndex {
|
||||
fun findMethodsByName(name: Name): Collection<JavaMethod>
|
||||
fun getMethodNames(): Set<Name>
|
||||
|
||||
fun findFieldByName(name: Name): JavaField?
|
||||
fun getFieldNames(): Set<Name>
|
||||
|
||||
object Empty : DeclaredMemberIndex {
|
||||
override fun findMethodsByName(name: Name) = listOf<JavaMethod>()
|
||||
override fun getMethodNames() = emptySet<Name>()
|
||||
|
||||
override fun findFieldByName(name: Name): JavaField? = null
|
||||
override fun getFieldNames() = emptySet<Name>()
|
||||
}
|
||||
}
|
||||
|
||||
open class ClassDeclaredMemberIndex(
|
||||
val jClass: JavaClass,
|
||||
private val memberFilter: (JavaMember) -> Boolean
|
||||
) : DeclaredMemberIndex {
|
||||
private val methodFilter = {
|
||||
m: JavaMethod ->
|
||||
memberFilter(m) && !DescriptorResolverUtils.isObjectMethodInInterface(m)
|
||||
}
|
||||
|
||||
private val methods = jClass.methods.asSequence().filter(methodFilter).groupBy { m -> m.name }
|
||||
private val fields = jClass.fields.asSequence().filter(memberFilter).associateBy { m -> m.name }
|
||||
|
||||
override fun findMethodsByName(name: Name): Collection<JavaMethod> = methods[name] ?: listOf()
|
||||
override fun getMethodNames(): Set<Name> = jClass.methods.asSequence().filter(methodFilter).mapTo(mutableSetOf(), JavaMethod::name)
|
||||
|
||||
override fun findFieldByName(name: Name): JavaField? = fields[name]
|
||||
override fun getFieldNames(): Set<Name> = jClass.fields.asSequence().filter(memberFilter).mapTo(mutableSetOf(), JavaField::name)
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.lazy.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
|
||||
|
||||
// Currently getter is null iff it's loaded from Java field
|
||||
val PropertyDescriptor.isJavaField: Boolean
|
||||
get() = getter == null
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.lazy.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.incremental.record
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.flatMapClassifierNamesOrNull
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
import org.jetbrains.kotlin.util.collectionUtils.getFirstClassifierDiscriminateHeaders
|
||||
import org.jetbrains.kotlin.util.collectionUtils.getFromAllScopes
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
|
||||
class JvmPackageScope(
|
||||
private val c: LazyJavaResolverContext,
|
||||
jPackage: JavaPackage,
|
||||
private val packageFragment: LazyJavaPackageFragment
|
||||
): MemberScope {
|
||||
internal val javaScope = LazyJavaPackageScope(c, jPackage, packageFragment)
|
||||
|
||||
private val kotlinScopes by c.storageManager.createLazyValue {
|
||||
packageFragment.binaryClasses.values.mapNotNull { partClass ->
|
||||
c.components.deserializedDescriptorResolver.createKotlinPackagePartScope(packageFragment, partClass)
|
||||
}.toList()
|
||||
}
|
||||
|
||||
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? {
|
||||
recordLookup(name, location)
|
||||
|
||||
val javaClassifier = javaScope.getContributedClassifier(name, location)
|
||||
if (javaClassifier != null) return javaClassifier
|
||||
|
||||
return getFirstClassifierDiscriminateHeaders(kotlinScopes) { it.getContributedClassifier(name, location) }
|
||||
}
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
|
||||
recordLookup(name, location)
|
||||
return getFromAllScopes(javaScope, kotlinScopes) { it.getContributedVariables(name, location) }
|
||||
}
|
||||
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> {
|
||||
recordLookup(name, location)
|
||||
return getFromAllScopes(javaScope, kotlinScopes) { it.getContributedFunctions(name, location) }
|
||||
}
|
||||
|
||||
override fun getContributedDescriptors(
|
||||
kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean
|
||||
): Collection<DeclarationDescriptor> =
|
||||
getFromAllScopes(javaScope, kotlinScopes) { it.getContributedDescriptors(kindFilter, nameFilter) }
|
||||
|
||||
override fun getFunctionNames() = kotlinScopes.flatMapTo(mutableSetOf()) { it.getFunctionNames() }.apply {
|
||||
addAll(javaScope.getFunctionNames())
|
||||
}
|
||||
override fun getVariableNames() = kotlinScopes.flatMapTo(mutableSetOf()) { it.getVariableNames() }.apply {
|
||||
addAll(javaScope.getVariableNames())
|
||||
}
|
||||
|
||||
override fun getClassifierNames(): Set<Name>? = kotlinScopes.flatMapClassifierNamesOrNull()?.apply {
|
||||
addAll(javaScope.getClassifierNames())
|
||||
}
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.println(this::class.java.simpleName, " {")
|
||||
p.pushIndent()
|
||||
|
||||
p.println("containingDeclaration: $packageFragment")
|
||||
javaScope.printScopeStructure(p)
|
||||
|
||||
for (kotlinScope in kotlinScopes) {
|
||||
kotlinScope.printScopeStructure(p)
|
||||
}
|
||||
|
||||
p.popIndent()
|
||||
p.println("}")
|
||||
}
|
||||
|
||||
override fun recordLookup(name: Name, location: LookupLocation) {
|
||||
c.components.lookupTracker.record(location, packageFragment, name)
|
||||
}
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.lazy.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.findNonGenericClassAcrossDependencies
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME
|
||||
import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.toAttributes
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
import org.jetbrains.kotlin.types.*
|
||||
|
||||
class LazyJavaAnnotationDescriptor(
|
||||
private val c: LazyJavaResolverContext,
|
||||
private val javaAnnotation: JavaAnnotation
|
||||
) : AnnotationDescriptor {
|
||||
override val fqName by c.storageManager.createNullableLazyValue {
|
||||
javaAnnotation.classId?.asSingleFqName()
|
||||
}
|
||||
|
||||
override val type by c.storageManager.createLazyValue {
|
||||
val fqName = fqName ?: return@createLazyValue ErrorUtils.createErrorType("No fqName: $javaAnnotation")
|
||||
val annotationClass = JavaToKotlinClassMap.mapJavaToKotlin(fqName, c.module.builtIns)
|
||||
?: javaAnnotation.resolve()?.let { javaClass -> c.components.moduleClassResolver.resolveClass(javaClass) }
|
||||
?: createTypeForMissingDependencies(fqName)
|
||||
annotationClass.defaultType
|
||||
}
|
||||
|
||||
override val source = c.components.sourceElementFactory.source(javaAnnotation)
|
||||
|
||||
private val factory = ConstantValueFactory(c.module.builtIns)
|
||||
|
||||
override val allValueArguments by c.storageManager.createLazyValue {
|
||||
javaAnnotation.arguments.mapNotNull { arg ->
|
||||
val name = arg.name ?: DEFAULT_ANNOTATION_MEMBER_NAME
|
||||
resolveAnnotationArgument(arg)?.let { value -> name to value }
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
private fun resolveAnnotationArgument(argument: JavaAnnotationArgument?): ConstantValue<*>? {
|
||||
return when (argument) {
|
||||
is JavaLiteralAnnotationArgument -> factory.createConstantValue(argument.value)
|
||||
is JavaEnumValueAnnotationArgument -> resolveFromEnumValue(argument.resolve(), argument.entryName)
|
||||
is JavaArrayAnnotationArgument -> resolveFromArray(argument.name ?: DEFAULT_ANNOTATION_MEMBER_NAME, argument.getElements())
|
||||
is JavaAnnotationAsAnnotationArgument -> resolveFromAnnotation(argument.getAnnotation())
|
||||
is JavaClassObjectAnnotationArgument -> resolveFromJavaClassObjectType(argument.getReferencedType())
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveFromAnnotation(javaAnnotation: JavaAnnotation): ConstantValue<*> {
|
||||
return factory.createAnnotationValue(LazyJavaAnnotationDescriptor(c, javaAnnotation))
|
||||
}
|
||||
|
||||
private fun resolveFromArray(argumentName: Name, elements: List<JavaAnnotationArgument>): ConstantValue<*>? {
|
||||
if (type.isError) return null
|
||||
|
||||
val arrayType =
|
||||
DescriptorResolverUtils.getAnnotationParameterByName(argumentName, annotationClass!!)?.type
|
||||
// Try to load annotation arguments even if the annotation class is not found
|
||||
?: c.components.module.builtIns.getArrayType(
|
||||
Variance.INVARIANT,
|
||||
ErrorUtils.createErrorType("Unknown array element type")
|
||||
)
|
||||
|
||||
val values = elements.map {
|
||||
argument -> resolveAnnotationArgument(argument) ?: factory.createNullValue()
|
||||
}
|
||||
|
||||
return factory.createArrayValue(values, arrayType)
|
||||
}
|
||||
|
||||
private fun resolveFromEnumValue(element: JavaField?, entryName: Name?): ConstantValue<*>? {
|
||||
if (element == null || !element.isEnumEntry) {
|
||||
if (entryName == null) return null
|
||||
return factory.createEnumValue(ErrorUtils.createErrorClassWithExactName(entryName))
|
||||
}
|
||||
|
||||
val containingJavaClass = element.containingClass
|
||||
|
||||
val enumClass = c.components.moduleClassResolver.resolveClass(containingJavaClass) ?: return null
|
||||
|
||||
val classifier = enumClass.unsubstitutedInnerClassesScope.getContributedClassifier(element.name, NoLookupLocation.FROM_JAVA_LOADER)
|
||||
as? ClassDescriptor ?: return null
|
||||
|
||||
return factory.createEnumValue(classifier)
|
||||
}
|
||||
|
||||
private fun resolveFromJavaClassObjectType(javaType: JavaType): ConstantValue<*>? {
|
||||
// Class type is never nullable in 'Foo.class' in Java
|
||||
val type = TypeUtils.makeNotNullable(c.typeResolver.transformJavaType(
|
||||
javaType,
|
||||
TypeUsage.COMMON.toAttributes())
|
||||
)
|
||||
|
||||
val jlClass = c.module.resolveTopLevelClass(FqName("java.lang.Class"), NoLookupLocation.FOR_NON_TRACKED_SCOPE) ?: return null
|
||||
|
||||
val arguments = listOf(TypeProjectionImpl(type))
|
||||
|
||||
val javaClassObjectType = KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, jlClass, arguments)
|
||||
|
||||
return factory.createKClassValue(javaClassObjectType)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return DescriptorRenderer.FQ_NAMES_IN_TYPES.renderAnnotation(this)
|
||||
}
|
||||
|
||||
private fun createTypeForMissingDependencies(fqName: FqName) =
|
||||
c.module.findNonGenericClassAcrossDependencies(
|
||||
ClassId.topLevel(fqName),
|
||||
c.components.deserializedDescriptorResolver.components.notFoundClasses
|
||||
)
|
||||
}
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.lazy.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorBase
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.FakePureImplementationsProvider
|
||||
import org.jetbrains.kotlin.load.java.JavaVisibilities
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.components.JavaResolverCache
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.lazy.childForClassOrPackage
|
||||
import org.jetbrains.kotlin.load.java.lazy.replaceComponents
|
||||
import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.toAttributes
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClassifierType
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaType
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.isValidJavaFqName
|
||||
import org.jetbrains.kotlin.platform.createMappedTypeParametersSubstitution
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass
|
||||
import org.jetbrains.kotlin.resolve.scopes.InnerClassesScopeWrapper
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import java.util.*
|
||||
|
||||
class LazyJavaClassDescriptor(
|
||||
outerContext: LazyJavaResolverContext,
|
||||
containingDeclaration: DeclarationDescriptor,
|
||||
private val jClass: JavaClass,
|
||||
private val additionalSupertypeClassDescriptor: ClassDescriptor? = null
|
||||
) : ClassDescriptorBase(outerContext.storageManager, containingDeclaration, jClass.name,
|
||||
outerContext.components.sourceElementFactory.source(jClass),
|
||||
/* isExternal = */ false), JavaClassDescriptor {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
private val PUBLIC_METHOD_NAMES_IN_OBJECT = setOf("equals", "hashCode", "getClass", "wait", "notify", "notifyAll", "toString")
|
||||
}
|
||||
|
||||
private val c: LazyJavaResolverContext = outerContext.childForClassOrPackage(this, jClass)
|
||||
|
||||
init {
|
||||
c.components.javaResolverCache.recordClass(jClass, this)
|
||||
|
||||
assert(jClass.lightClassOriginKind == null) {
|
||||
"Creating LazyJavaClassDescriptor for light class $jClass"
|
||||
}
|
||||
}
|
||||
|
||||
private val kind = when {
|
||||
jClass.isAnnotationType -> ClassKind.ANNOTATION_CLASS
|
||||
jClass.isInterface -> ClassKind.INTERFACE
|
||||
jClass.isEnum -> ClassKind.ENUM_CLASS
|
||||
else -> ClassKind.CLASS
|
||||
}
|
||||
|
||||
private val modality = if (jClass.isAnnotationType)
|
||||
Modality.FINAL
|
||||
else Modality.convertFromFlags(jClass.isAbstract || jClass.isInterface, !jClass.isFinal)
|
||||
|
||||
private val visibility = jClass.visibility
|
||||
private val isInner = jClass.outerClass != null && !jClass.isStatic
|
||||
|
||||
override fun getKind() = kind
|
||||
override fun getModality() = modality
|
||||
|
||||
// To workaround a problem with Scala compatibility (KT-9700),
|
||||
// we consider private visibility of a Java top level class as package private
|
||||
// Shortly: Scala plugin introduces special kind of "private in package" classes
|
||||
// which can be inherited from the same package.
|
||||
// Kotlin considers this "private in package" just as "private" and thinks they are invisible for inheritors,
|
||||
// so their functions are invisible fake which is not true.
|
||||
override fun getVisibility() =
|
||||
if (visibility == Visibilities.PRIVATE && jClass.outerClass == null) JavaVisibilities.PACKAGE_VISIBILITY else visibility
|
||||
|
||||
override fun isInner() = isInner
|
||||
override fun isData() = false
|
||||
override fun isCompanionObject() = false
|
||||
override fun isExpect() = false
|
||||
override fun isActual() = false
|
||||
|
||||
private val typeConstructor = LazyJavaClassTypeConstructor()
|
||||
override fun getTypeConstructor(): TypeConstructor = typeConstructor
|
||||
|
||||
private val unsubstitutedMemberScope = LazyJavaClassMemberScope(c, this, jClass)
|
||||
override fun getUnsubstitutedMemberScope() = unsubstitutedMemberScope
|
||||
|
||||
private val innerClassesScope = InnerClassesScopeWrapper(getUnsubstitutedMemberScope())
|
||||
override fun getUnsubstitutedInnerClassesScope(): MemberScope = innerClassesScope
|
||||
|
||||
private val staticScope = LazyJavaStaticClassScope(c, jClass, this)
|
||||
override fun getStaticScope(): MemberScope = staticScope
|
||||
|
||||
override fun getUnsubstitutedPrimaryConstructor(): ClassConstructorDescriptor? = null
|
||||
|
||||
override fun getCompanionObjectDescriptor(): ClassDescriptor? = null
|
||||
|
||||
override fun getConstructors() = unsubstitutedMemberScope.constructors()
|
||||
|
||||
override val annotations = c.resolveAnnotations(jClass)
|
||||
|
||||
private val declaredParameters = c.storageManager.createLazyValue {
|
||||
jClass.typeParameters.map {
|
||||
p ->
|
||||
c.typeParameterResolver.resolveTypeParameter(p)
|
||||
?: throw AssertionError("Parameter $p surely belongs to class $jClass, so it must be resolved")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDeclaredTypeParameters() = declaredParameters()
|
||||
|
||||
override fun getDefaultFunctionTypeForSamInterface(): SimpleType? = c.components.samConversionResolver.resolveFunctionTypeIfSamInterface(this)
|
||||
|
||||
override fun isDefinitelyNotSamInterface(): Boolean {
|
||||
if (kind != ClassKind.INTERFACE) return true
|
||||
|
||||
val candidates = jClass.methods.filter { it.isAbstract && it.typeParameters.isEmpty() }
|
||||
// From the definition of function interfaces in the Java specification (pt. 9.8):
|
||||
// "methods that are members of I that do not have the same signature as any public instance method of the class Object"
|
||||
// It means that if an interface declares `int hashCode()` then the method won't be taken into account when
|
||||
// checking if the interface is SAM.
|
||||
// We make here a conservative check just filtering out methods by name.
|
||||
// If we ignore a method with wrong signature (different from one in Object) it's not very bad,
|
||||
// we'll just say that the interface MAY BE a SAM when it's not and then more detailed check will be applied.
|
||||
if (candidates.count { it.name.identifier !in PUBLIC_METHOD_NAMES_IN_OBJECT } > 1) return true
|
||||
|
||||
// Check if any of the super-interfaces contain too many methods to be a SAM
|
||||
return typeConstructor.supertypes.any {
|
||||
it.constructor.declarationDescriptor.safeAs<LazyJavaClassDescriptor>()?.isDefinitelyNotSamInterface == true
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSealedSubclasses(): Collection<ClassDescriptor> = emptyList()
|
||||
|
||||
override fun toString() = "Lazy Java class ${this.fqNameUnsafe}"
|
||||
|
||||
private inner class LazyJavaClassTypeConstructor : AbstractClassTypeConstructor(c.storageManager) {
|
||||
private val parameters = c.storageManager.createLazyValue {
|
||||
this@LazyJavaClassDescriptor.computeConstructorTypeParameters()
|
||||
}
|
||||
|
||||
override fun getParameters(): List<TypeParameterDescriptor> = parameters()
|
||||
|
||||
override fun computeSupertypes(): Collection<KotlinType> {
|
||||
val javaTypes = jClass.supertypes
|
||||
val result = ArrayList<KotlinType>(javaTypes.size)
|
||||
val incomplete = ArrayList<JavaType>(0)
|
||||
|
||||
val purelyImplementedSupertype: KotlinType? = getPurelyImplementedSupertype()
|
||||
|
||||
for (javaType in javaTypes) {
|
||||
val kotlinType = c.typeResolver.transformJavaType(javaType, TypeUsage.SUPERTYPE.toAttributes())
|
||||
if (kotlinType.constructor.declarationDescriptor is NotFoundClasses.MockClassDescriptor) {
|
||||
incomplete.add(javaType)
|
||||
}
|
||||
|
||||
if (kotlinType.constructor == purelyImplementedSupertype?.constructor) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (!KotlinBuiltIns.isAnyOrNullableAny(kotlinType)) {
|
||||
result.add(kotlinType)
|
||||
}
|
||||
}
|
||||
|
||||
// Add fake supertype kotlin.collection.Collection<E> to java.util.Collection<E> class if needed
|
||||
// Only needed when calculating built-ins member scope
|
||||
result.addIfNotNull(
|
||||
additionalSupertypeClassDescriptor?.let {
|
||||
createMappedTypeParametersSubstitution(it, this@LazyJavaClassDescriptor)
|
||||
.buildSubstitutor().substitute(it.defaultType, Variance.INVARIANT)
|
||||
})
|
||||
|
||||
result.addIfNotNull(purelyImplementedSupertype)
|
||||
|
||||
if (incomplete.isNotEmpty()) {
|
||||
c.components.errorReporter.reportIncompleteHierarchy(declarationDescriptor, incomplete.map { javaType ->
|
||||
(javaType as JavaClassifierType).presentableText
|
||||
})
|
||||
}
|
||||
|
||||
return if (result.isNotEmpty()) result.toList() else listOf(c.module.builtIns.anyType)
|
||||
}
|
||||
|
||||
private fun getPurelyImplementedSupertype(): KotlinType? {
|
||||
val annotatedPurelyImplementedFqName = getPurelyImplementsFqNameFromAnnotation()?.takeIf { fqName ->
|
||||
!fqName.isRoot && fqName.startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME)
|
||||
}
|
||||
|
||||
val purelyImplementedFqName =
|
||||
annotatedPurelyImplementedFqName
|
||||
?: FakePureImplementationsProvider.getPurelyImplementedInterface(fqNameSafe)
|
||||
?: return null
|
||||
|
||||
val classDescriptor = c.module.resolveTopLevelClass(purelyImplementedFqName, NoLookupLocation.FROM_JAVA_LOADER) ?: return null
|
||||
|
||||
val supertypeParameterCount = classDescriptor.typeConstructor.parameters.size
|
||||
val typeParameters = getTypeConstructor().parameters
|
||||
val typeParameterCount = typeParameters.size
|
||||
|
||||
val parametersAsTypeProjections = when {
|
||||
typeParameterCount == supertypeParameterCount ->
|
||||
typeParameters.map {
|
||||
parameter ->
|
||||
TypeProjectionImpl(Variance.INVARIANT, parameter.defaultType)
|
||||
}
|
||||
typeParameterCount == 1 && supertypeParameterCount > 1 && annotatedPurelyImplementedFqName == null ->
|
||||
{
|
||||
val parameter = TypeProjectionImpl(Variance.INVARIANT, typeParameters.single().defaultType)
|
||||
(1..supertypeParameterCount).map { parameter } // TODO: List(supertypeParameterCount) { parameter }
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
|
||||
return KotlinTypeFactory.simpleNotNullType(Annotations.EMPTY, classDescriptor, parametersAsTypeProjections)
|
||||
}
|
||||
|
||||
private fun getPurelyImplementsFqNameFromAnnotation(): FqName? {
|
||||
val annotation =
|
||||
this@LazyJavaClassDescriptor.annotations.findAnnotation(JvmAnnotationNames.PURELY_IMPLEMENTS_ANNOTATION)
|
||||
?: return null
|
||||
|
||||
val fqNameString = (annotation.allValueArguments.values.singleOrNull() as? StringValue)?.value ?: return null
|
||||
if (!isValidJavaFqName(fqNameString)) return null
|
||||
|
||||
return FqName(fqNameString)
|
||||
}
|
||||
|
||||
override val supertypeLoopChecker: SupertypeLoopChecker
|
||||
get() = c.components.supertypeLoopChecker
|
||||
|
||||
override fun isDenotable(): Boolean = true
|
||||
|
||||
override fun getDeclarationDescriptor(): ClassDescriptor = this@LazyJavaClassDescriptor
|
||||
|
||||
override fun toString(): String = name.asString()
|
||||
}
|
||||
|
||||
// Only needed when calculating built-ins member scope
|
||||
internal fun copy(
|
||||
javaResolverCache: JavaResolverCache, additionalSupertypeClassDescriptor: ClassDescriptor?
|
||||
) = LazyJavaClassDescriptor(
|
||||
c.replaceComponents(c.components.replace(javaResolverCache = javaResolverCache)),
|
||||
containingDeclaration, jClass, additionalSupertypeClassDescriptor)
|
||||
}
|
||||
+680
@@ -0,0 +1,680 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.lazy.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.incremental.record
|
||||
import org.jetbrains.kotlin.load.java.*
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithDifferentJvmName.isRemoveAtByIndex
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithDifferentJvmName.sameAsRenamedInJvmBuiltin
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.sameAsBuiltinMethodWithErasedValueParameters
|
||||
import org.jetbrains.kotlin.load.java.BuiltinSpecialProperties.getBuiltinSpecialPropertyGetterName
|
||||
import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils.resolveOverridesForNonStaticMembers
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage
|
||||
import org.jetbrains.kotlin.load.java.descriptors.*
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.lazy.childForMethod
|
||||
import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.toAttributes
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaArrayType
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaConstructor
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod
|
||||
import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
|
||||
import org.jetbrains.kotlin.storage.NotNullLazyValue
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
import org.jetbrains.kotlin.utils.ifEmpty
|
||||
import java.util.*
|
||||
|
||||
class LazyJavaClassMemberScope(
|
||||
c: LazyJavaResolverContext,
|
||||
override val ownerDescriptor: ClassDescriptor,
|
||||
private val jClass: JavaClass
|
||||
) : LazyJavaScope(c) {
|
||||
|
||||
override fun computeMemberIndex() = ClassDeclaredMemberIndex(jClass, { !it.isStatic })
|
||||
|
||||
override fun computeFunctionNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?) =
|
||||
ownerDescriptor.typeConstructor.supertypes.flatMapTo(HashSet()) {
|
||||
it.memberScope.getFunctionNames()
|
||||
}.apply {
|
||||
addAll(declaredMemberIndex().getMethodNames())
|
||||
addAll(computeClassNames(kindFilter, nameFilter))
|
||||
}
|
||||
|
||||
internal val constructors = c.storageManager.createLazyValue {
|
||||
val constructors = jClass.constructors
|
||||
val result = ArrayList<JavaClassConstructorDescriptor>(constructors.size)
|
||||
for (constructor in constructors) {
|
||||
val descriptor = resolveConstructor(constructor)
|
||||
result.add(descriptor)
|
||||
}
|
||||
|
||||
c.components.signatureEnhancement.enhanceSignatures(
|
||||
c,
|
||||
result.ifEmpty { listOfNotNull(createDefaultConstructor()) }
|
||||
).toList()
|
||||
}
|
||||
|
||||
override fun JavaMethodDescriptor.isVisibleAsFunction(): Boolean {
|
||||
if (jClass.isAnnotationType) return false
|
||||
return isVisibleAsFunctionInCurrentClass(this)
|
||||
}
|
||||
|
||||
private fun isVisibleAsFunctionInCurrentClass(function: SimpleFunctionDescriptor): Boolean {
|
||||
if (getPropertyNamesCandidatesByAccessorName(function.name).any {
|
||||
propertyName ->
|
||||
getPropertiesFromSupertypes(propertyName).any {
|
||||
property ->
|
||||
doesClassOverridesProperty(property) {
|
||||
accessorName ->
|
||||
// This lambda should return property accessors available in this class by their name
|
||||
// If 'accessorName' is current function we return only it just because we check exactly
|
||||
// that current method is override of accessor
|
||||
if (function.name == accessorName)
|
||||
listOf(function)
|
||||
else
|
||||
searchMethodsByNameWithoutBuiltinMagic(accessorName) + searchMethodsInSupertypesWithoutBuiltinMagic(accessorName)
|
||||
} && (property.isVar || !JvmAbi.isSetterName(function.name.asString()))
|
||||
}
|
||||
}) return false
|
||||
|
||||
return !function.doesOverrideRenamedBuiltins() && !function.shouldBeVisibleAsOverrideOfBuiltInWithErasedValueParameters()
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if function is a valid override of JDK analogue of built-in method with erased value parameters (e.g. Map.containsKey(k: K))
|
||||
*
|
||||
* Examples:
|
||||
* - boolean containsKey(Object key) -> true
|
||||
* - boolean containsKey(K key) -> false // Wrong JDK method override, while it's a valid Kotlin built-in override
|
||||
*/
|
||||
private fun SimpleFunctionDescriptor.shouldBeVisibleAsOverrideOfBuiltInWithErasedValueParameters(): Boolean {
|
||||
if (!name.sameAsBuiltinMethodWithErasedValueParameters) return false
|
||||
val candidatesToOverride =
|
||||
getFunctionsFromSupertypes(name).mapNotNull {
|
||||
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(it)
|
||||
}
|
||||
|
||||
return candidatesToOverride.any {
|
||||
candidate ->
|
||||
hasSameJvmDescriptorButDoesNotOverride(candidate)
|
||||
}
|
||||
}
|
||||
|
||||
private fun searchMethodsByNameWithoutBuiltinMagic(name: Name): Collection<SimpleFunctionDescriptor> =
|
||||
declaredMemberIndex().findMethodsByName(name).map { resolveMethodToFunctionDescriptor(it) }
|
||||
|
||||
private fun searchMethodsInSupertypesWithoutBuiltinMagic(name: Name): Collection<SimpleFunctionDescriptor> =
|
||||
getFunctionsFromSupertypes(name).filterNot {
|
||||
it.doesOverrideBuiltinWithDifferentJvmName()
|
||||
|| BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(it) != null
|
||||
}
|
||||
|
||||
private fun SimpleFunctionDescriptor.doesOverrideRenamedBuiltins(): Boolean {
|
||||
return BuiltinMethodsWithDifferentJvmName.getBuiltinFunctionNamesByJvmName(name).any {
|
||||
// e.g. 'removeAt' or 'toInt'
|
||||
builtinName ->
|
||||
val builtinSpecialFromSuperTypes =
|
||||
getFunctionsFromSupertypes(builtinName).filter { it.doesOverrideBuiltinWithDifferentJvmName() }
|
||||
if (builtinSpecialFromSuperTypes.isEmpty()) return@any false
|
||||
|
||||
val methodDescriptor = this.createRenamedCopy(builtinName)
|
||||
|
||||
builtinSpecialFromSuperTypes.any { doesOverrideRenamedDescriptor(it, methodDescriptor) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun SimpleFunctionDescriptor.createRenamedCopy(builtinName: Name): SimpleFunctionDescriptor =
|
||||
this.newCopyBuilder().apply {
|
||||
setName(builtinName)
|
||||
setSignatureChange()
|
||||
setPreserveSourceElement()
|
||||
}.build()!!
|
||||
|
||||
private fun doesOverrideRenamedDescriptor(
|
||||
superDescriptor: SimpleFunctionDescriptor,
|
||||
subDescriptor: FunctionDescriptor
|
||||
): Boolean {
|
||||
// if we check 'removeAt', get original sub-descriptor to distinct `remove(int)` and `remove(E)` in Java
|
||||
val subDescriptorToCheck = if (superDescriptor.isRemoveAtByIndex) subDescriptor.original else subDescriptor
|
||||
|
||||
return subDescriptorToCheck.doesOverride(superDescriptor)
|
||||
}
|
||||
|
||||
private fun CallableDescriptor.doesOverride(superDescriptor: CallableDescriptor): Boolean {
|
||||
val commonOverridabilityResult =
|
||||
OverridingUtil.DEFAULT.isOverridableByWithoutExternalConditions(superDescriptor, this, true).result
|
||||
|
||||
return commonOverridabilityResult == OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE &&
|
||||
!JavaIncompatibilityRulesOverridabilityCondition.doesJavaOverrideHaveIncompatibleValueParameterKinds(
|
||||
superDescriptor, this)
|
||||
}
|
||||
|
||||
private fun PropertyDescriptor.findGetterOverride(
|
||||
functions: (Name) -> Collection<SimpleFunctionDescriptor>
|
||||
): SimpleFunctionDescriptor? {
|
||||
val overriddenBuiltinProperty = getter?.getOverriddenBuiltinWithDifferentJvmName()
|
||||
val specialGetterName = overriddenBuiltinProperty?.getBuiltinSpecialPropertyGetterName()
|
||||
if (specialGetterName != null
|
||||
&& !this@LazyJavaClassMemberScope.ownerDescriptor.hasRealKotlinSuperClassWithOverrideOf(overriddenBuiltinProperty)
|
||||
) {
|
||||
return findGetterByName(specialGetterName, functions)
|
||||
}
|
||||
|
||||
return findGetterByName(JvmAbi.getterName(name.asString()), functions)
|
||||
}
|
||||
|
||||
private fun PropertyDescriptor.findGetterByName(
|
||||
getterName: String,
|
||||
functions: (Name) -> Collection<SimpleFunctionDescriptor>
|
||||
): SimpleFunctionDescriptor? {
|
||||
return functions(Name.identifier(getterName)).firstNotNullResult factory@{
|
||||
descriptor ->
|
||||
if (descriptor.valueParameters.size != 0) return@factory null
|
||||
|
||||
descriptor.takeIf { KotlinTypeChecker.DEFAULT.isSubtypeOf(descriptor.returnType ?: return@takeIf false, type) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun PropertyDescriptor.findSetterOverride(
|
||||
functions: (Name) -> Collection<SimpleFunctionDescriptor>
|
||||
): SimpleFunctionDescriptor? {
|
||||
return functions(Name.identifier(JvmAbi.setterName(name.asString()))).firstNotNullResult factory@{
|
||||
descriptor ->
|
||||
if (descriptor.valueParameters.size != 1) return@factory null
|
||||
|
||||
if (!KotlinBuiltIns.isUnit(descriptor.returnType ?: return@factory null)) return@factory null
|
||||
descriptor.takeIf { KotlinTypeChecker.DEFAULT.equalTypes(descriptor.valueParameters.single().type, type) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun doesClassOverridesProperty(
|
||||
property: PropertyDescriptor,
|
||||
functions: (Name) -> Collection<SimpleFunctionDescriptor>
|
||||
): Boolean {
|
||||
if (property.isJavaField) return false
|
||||
val getter = property.findGetterOverride(functions)
|
||||
val setter = property.findSetterOverride(functions)
|
||||
|
||||
if (getter == null) return false
|
||||
if (!property.isVar) return true
|
||||
|
||||
return setter != null && setter.modality == getter.modality
|
||||
}
|
||||
|
||||
override fun computeNonDeclaredFunctions(result: MutableCollection<SimpleFunctionDescriptor>, name: Name) {
|
||||
val functionsFromSupertypes = getFunctionsFromSupertypes(name)
|
||||
|
||||
if (!name.sameAsRenamedInJvmBuiltin && !name.sameAsBuiltinMethodWithErasedValueParameters) {
|
||||
// Simple fast path in case of name is not suspicious (i.e. name is not one of builtins that have different signature in Java)
|
||||
addFunctionFromSupertypes(
|
||||
result, name,
|
||||
functionsFromSupertypes.filter { isVisibleAsFunctionInCurrentClass(it) },
|
||||
isSpecialBuiltinName = false)
|
||||
return
|
||||
}
|
||||
|
||||
val specialBuiltinsFromSuperTypes = SmartSet.create<SimpleFunctionDescriptor>()
|
||||
|
||||
// Merge functions with same signatures
|
||||
val mergedFunctionFromSuperTypes = resolveOverridesForNonStaticMembers(
|
||||
name, functionsFromSupertypes, emptyList(), ownerDescriptor, ErrorReporter.DO_NOTHING)
|
||||
|
||||
// add declarations
|
||||
addOverriddenBuiltinMethods(
|
||||
name, result, mergedFunctionFromSuperTypes, result,
|
||||
this::searchMethodsByNameWithoutBuiltinMagic)
|
||||
|
||||
// add from super types
|
||||
addOverriddenBuiltinMethods(
|
||||
name, result, mergedFunctionFromSuperTypes, specialBuiltinsFromSuperTypes,
|
||||
this::searchMethodsInSupertypesWithoutBuiltinMagic)
|
||||
|
||||
val visibleFunctionsFromSupertypes =
|
||||
functionsFromSupertypes.filter { isVisibleAsFunctionInCurrentClass(it) } + specialBuiltinsFromSuperTypes
|
||||
|
||||
addFunctionFromSupertypes(result, name, visibleFunctionsFromSupertypes, isSpecialBuiltinName = true)
|
||||
}
|
||||
|
||||
private fun addFunctionFromSupertypes(
|
||||
result: MutableCollection<SimpleFunctionDescriptor>,
|
||||
name: Name,
|
||||
functionsFromSupertypes: Collection<SimpleFunctionDescriptor>,
|
||||
isSpecialBuiltinName: Boolean
|
||||
) {
|
||||
|
||||
val additionalOverrides = resolveOverridesForNonStaticMembers(
|
||||
name, functionsFromSupertypes, result, ownerDescriptor, c.components.errorReporter
|
||||
)
|
||||
|
||||
if (!isSpecialBuiltinName) {
|
||||
result.addAll(additionalOverrides)
|
||||
}
|
||||
else {
|
||||
val allDescriptors = result + additionalOverrides
|
||||
result.addAll(
|
||||
additionalOverrides.map {
|
||||
resolvedOverride ->
|
||||
val overriddenBuiltin = resolvedOverride.getOverriddenSpecialBuiltin()
|
||||
?: return@map resolvedOverride
|
||||
|
||||
resolvedOverride.createHiddenCopyIfBuiltinAlreadyAccidentallyOverridden(overriddenBuiltin, allDescriptors)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun addOverriddenBuiltinMethods(
|
||||
name: Name,
|
||||
alreadyDeclaredFunctions: Collection<SimpleFunctionDescriptor>,
|
||||
candidatesForOverride: Collection<SimpleFunctionDescriptor>,
|
||||
result: MutableCollection<SimpleFunctionDescriptor>,
|
||||
functions: (Name) -> Collection<SimpleFunctionDescriptor>
|
||||
) {
|
||||
for (descriptor in candidatesForOverride) {
|
||||
val overriddenBuiltin = descriptor.getOverriddenBuiltinWithDifferentJvmName() ?: continue
|
||||
|
||||
val nameInJava = getJvmMethodNameIfSpecial(overriddenBuiltin)!!
|
||||
for (method in functions(Name.identifier(nameInJava))) {
|
||||
val renamedCopy = method.createRenamedCopy(name)
|
||||
|
||||
if (doesOverrideRenamedDescriptor(overriddenBuiltin, renamedCopy)) {
|
||||
result.add(
|
||||
renamedCopy.createHiddenCopyIfBuiltinAlreadyAccidentallyOverridden(overriddenBuiltin, alreadyDeclaredFunctions))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (descriptor in candidatesForOverride) {
|
||||
val overriddenBuiltin =
|
||||
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(descriptor)
|
||||
?: continue
|
||||
|
||||
createOverrideForBuiltinFunctionWithErasedParameterIfNeeded(overriddenBuiltin, functions)?.let {
|
||||
override ->
|
||||
if (isVisibleAsFunctionInCurrentClass(override)) {
|
||||
result.add(override.createHiddenCopyIfBuiltinAlreadyAccidentallyOverridden(overriddenBuiltin, alreadyDeclaredFunctions))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In case when Java has declaration with signature reflecting one of special builtin we load override of builtin as hidden function
|
||||
// Unless we do it then signature clash happens.
|
||||
// For example see java.nio.CharBuffer implementing CharSequence and defining irrelevant 'get' method having the same signature as in kotlin.CharSequence
|
||||
// We load java.nio.CharBuffer as having both 'get' functions, but one that is override of kotlin.CharSequence is hidden,
|
||||
// so when someone calls CharBuffer.get it results in invoking java method CharBuffer.get
|
||||
// But we still have the way to call 'charAt' java method by upcasting CharBuffer to kotlin.CharSequence
|
||||
private fun SimpleFunctionDescriptor.createHiddenCopyIfBuiltinAlreadyAccidentallyOverridden(
|
||||
specialBuiltin: CallableDescriptor,
|
||||
alreadyDeclaredFunctions: Collection<SimpleFunctionDescriptor>
|
||||
): SimpleFunctionDescriptor =
|
||||
if (alreadyDeclaredFunctions.none { this != it && it.initialSignatureDescriptor == null && it.doesOverride(specialBuiltin) })
|
||||
this
|
||||
else
|
||||
newCopyBuilder().setHiddenToOvercomeSignatureClash().build()!!
|
||||
|
||||
private fun createOverrideForBuiltinFunctionWithErasedParameterIfNeeded(
|
||||
overridden: FunctionDescriptor,
|
||||
functions: (Name) -> Collection<SimpleFunctionDescriptor>
|
||||
): SimpleFunctionDescriptor? {
|
||||
return functions(overridden.name).firstOrNull {
|
||||
it.hasSameJvmDescriptorButDoesNotOverride(overridden)
|
||||
}?.let {
|
||||
override ->
|
||||
override.newCopyBuilder().apply {
|
||||
setValueParameters(copyValueParameters(
|
||||
overridden.valueParameters.map { ValueParameterData(it.type, it.hasDefaultValue()) },
|
||||
override.valueParameters, overridden))
|
||||
setSignatureChange()
|
||||
setPreserveSourceElement()
|
||||
}.build()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFunctionsFromSupertypes(name: Name): Set<SimpleFunctionDescriptor> {
|
||||
return ownerDescriptor.typeConstructor.supertypes.flatMapTo(LinkedHashSet()) {
|
||||
it.memberScope.getContributedFunctions(name, NoLookupLocation.WHEN_GET_SUPER_MEMBERS)
|
||||
}
|
||||
}
|
||||
|
||||
override fun computeNonDeclaredProperties(name: Name, result: MutableCollection<PropertyDescriptor>) {
|
||||
if (jClass.isAnnotationType) {
|
||||
computeAnnotationProperties(name, result)
|
||||
}
|
||||
|
||||
val propertiesFromSupertypes = getPropertiesFromSupertypes(name)
|
||||
if (propertiesFromSupertypes.isEmpty()) return
|
||||
|
||||
val propertiesOverridesFromSuperTypes = SmartSet.create<PropertyDescriptor>()
|
||||
|
||||
addPropertyOverrideByMethod(propertiesFromSupertypes, result) { searchMethodsByNameWithoutBuiltinMagic(it) }
|
||||
|
||||
addPropertyOverrideByMethod(propertiesFromSupertypes, propertiesOverridesFromSuperTypes) {
|
||||
searchMethodsInSupertypesWithoutBuiltinMagic(it)
|
||||
}
|
||||
|
||||
result.addAll(resolveOverridesForNonStaticMembers(
|
||||
name, propertiesFromSupertypes + propertiesOverridesFromSuperTypes, result, ownerDescriptor, c.components.errorReporter))
|
||||
}
|
||||
|
||||
private fun addPropertyOverrideByMethod(
|
||||
propertiesFromSupertypes: Set<PropertyDescriptor>,
|
||||
result: MutableCollection<PropertyDescriptor>,
|
||||
functions: (Name) -> Collection<SimpleFunctionDescriptor>
|
||||
) {
|
||||
for (property in propertiesFromSupertypes) {
|
||||
val newProperty = createPropertyDescriptorByMethods(property, functions)
|
||||
if (newProperty != null) {
|
||||
result.add(newProperty)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeAnnotationProperties(name: Name, result: MutableCollection<PropertyDescriptor>) {
|
||||
val method = declaredMemberIndex().findMethodsByName(name).singleOrNull() ?: return
|
||||
result.add(createPropertyDescriptorWithDefaultGetter(method, modality = Modality.FINAL))
|
||||
}
|
||||
|
||||
private fun createPropertyDescriptorWithDefaultGetter(
|
||||
method: JavaMethod, givenType: KotlinType? = null, modality: Modality
|
||||
): JavaPropertyDescriptor {
|
||||
val annotations = c.resolveAnnotations(method)
|
||||
|
||||
val propertyDescriptor = JavaPropertyDescriptor.create(
|
||||
ownerDescriptor, annotations, modality, method.visibility,
|
||||
/* isVar = */ false, method.name, c.components.sourceElementFactory.source(method),
|
||||
/* isStaticFinal = */ false
|
||||
)
|
||||
|
||||
val getter = DescriptorFactory.createDefaultGetter(propertyDescriptor, Annotations.EMPTY)
|
||||
propertyDescriptor.initialize(getter, null)
|
||||
|
||||
val returnType = givenType ?: computeMethodReturnType(method, c.childForMethod(propertyDescriptor, method))
|
||||
propertyDescriptor.setType(returnType, listOf(), getDispatchReceiverParameter(), null as KotlinType?)
|
||||
getter.initialize(returnType)
|
||||
|
||||
return propertyDescriptor
|
||||
}
|
||||
|
||||
private fun createPropertyDescriptorByMethods(
|
||||
overriddenProperty: PropertyDescriptor,
|
||||
functions: (Name) -> Collection<SimpleFunctionDescriptor>
|
||||
): JavaPropertyDescriptor? {
|
||||
if (!doesClassOverridesProperty(overriddenProperty, functions)) return null
|
||||
|
||||
val getterMethod = overriddenProperty.findGetterOverride(functions)!!
|
||||
val setterMethod =
|
||||
if (overriddenProperty.isVar)
|
||||
overriddenProperty.findSetterOverride(functions)!!
|
||||
else
|
||||
null
|
||||
|
||||
assert(setterMethod?.let { it.modality == getterMethod.modality } ?: true) {
|
||||
"Different accessors modalities when creating overrides for $overriddenProperty in $ownerDescriptor" +
|
||||
"for getter is ${getterMethod.modality}, but for setter is ${setterMethod?.modality}"
|
||||
}
|
||||
|
||||
val propertyDescriptor = JavaPropertyDescriptor.create(
|
||||
ownerDescriptor, Annotations.EMPTY, getterMethod.modality, getterMethod.visibility,
|
||||
/* isVar = */ setterMethod != null, overriddenProperty.name, getterMethod.source,
|
||||
/* isStaticFinal = */ false
|
||||
)
|
||||
|
||||
propertyDescriptor.setType(getterMethod.returnType!!, listOf(), getDispatchReceiverParameter(), null as KotlinType?)
|
||||
|
||||
val getter = DescriptorFactory.createGetter(
|
||||
propertyDescriptor, getterMethod.annotations, /* isDefault = */false,
|
||||
/* isExternal = */ false, /* isInline = */ false, getterMethod.source
|
||||
).apply {
|
||||
initialSignatureDescriptor = getterMethod
|
||||
initialize(propertyDescriptor.type)
|
||||
}
|
||||
|
||||
val setter = setterMethod?.let { setterMethod ->
|
||||
DescriptorFactory.createSetter(propertyDescriptor, setterMethod.annotations, /* isDefault = */false,
|
||||
/* isExternal = */ false, /* isInline = */ false, setterMethod.visibility, setterMethod.source
|
||||
).apply {
|
||||
initialSignatureDescriptor = setterMethod
|
||||
}
|
||||
}
|
||||
|
||||
return propertyDescriptor.apply { initialize(getter, setter) }
|
||||
}
|
||||
|
||||
private fun getPropertiesFromSupertypes(name: Name): Set<PropertyDescriptor> {
|
||||
return ownerDescriptor.typeConstructor.supertypes.flatMap {
|
||||
it.memberScope.getContributedVariables(name, NoLookupLocation.WHEN_GET_SUPER_MEMBERS).map { p -> p }
|
||||
}.toSet()
|
||||
}
|
||||
|
||||
override fun resolveMethodSignature(
|
||||
method: JavaMethod, methodTypeParameters: List<TypeParameterDescriptor>, returnType: KotlinType,
|
||||
valueParameters: List<ValueParameterDescriptor>
|
||||
): LazyJavaScope.MethodSignatureData {
|
||||
val propagated = c.components.signaturePropagator.resolvePropagatedSignature(
|
||||
method, ownerDescriptor, returnType, null, valueParameters, methodTypeParameters
|
||||
)
|
||||
return LazyJavaScope.MethodSignatureData(
|
||||
propagated.returnType, propagated.receiverType, propagated.valueParameters, propagated.typeParameters,
|
||||
propagated.hasStableParameterNames(), propagated.errors
|
||||
)
|
||||
}
|
||||
|
||||
private fun SimpleFunctionDescriptor.hasSameJvmDescriptorButDoesNotOverride(
|
||||
builtinWithErasedParameters: FunctionDescriptor
|
||||
): Boolean {
|
||||
return computeJvmDescriptor(withReturnType = false) ==
|
||||
builtinWithErasedParameters.original.computeJvmDescriptor(withReturnType = false)
|
||||
&& !doesOverride(builtinWithErasedParameters)
|
||||
}
|
||||
|
||||
private fun resolveConstructor(constructor: JavaConstructor): JavaClassConstructorDescriptor {
|
||||
val classDescriptor = ownerDescriptor
|
||||
|
||||
val constructorDescriptor = JavaClassConstructorDescriptor.createJavaConstructor(
|
||||
classDescriptor, c.resolveAnnotations(constructor), /* isPrimary = */ false, c.components.sourceElementFactory.source(constructor)
|
||||
)
|
||||
|
||||
|
||||
val c = c.childForMethod(constructorDescriptor, constructor, typeParametersIndexOffset = classDescriptor.declaredTypeParameters.size)
|
||||
val valueParameters = resolveValueParameters(c, constructorDescriptor, constructor.valueParameters)
|
||||
val constructorTypeParameters =
|
||||
classDescriptor.declaredTypeParameters +
|
||||
constructor.typeParameters.map { p -> c.typeParameterResolver.resolveTypeParameter(p)!! }
|
||||
|
||||
constructorDescriptor.initialize(valueParameters.descriptors, constructor.visibility, constructorTypeParameters)
|
||||
constructorDescriptor.setHasStableParameterNames(false)
|
||||
constructorDescriptor.setHasSynthesizedParameterNames(valueParameters.hasSynthesizedNames)
|
||||
|
||||
constructorDescriptor.returnType = classDescriptor.defaultType
|
||||
|
||||
c.components.javaResolverCache.recordConstructor(constructor, constructorDescriptor)
|
||||
|
||||
return constructorDescriptor
|
||||
}
|
||||
|
||||
private fun createDefaultConstructor(): ClassConstructorDescriptor? {
|
||||
val isAnnotation: Boolean = jClass.isAnnotationType
|
||||
if (jClass.isInterface && !isAnnotation)
|
||||
return null
|
||||
|
||||
val classDescriptor = ownerDescriptor
|
||||
val constructorDescriptor = JavaClassConstructorDescriptor.createJavaConstructor(
|
||||
classDescriptor, Annotations.EMPTY, /* isPrimary = */ true, c.components.sourceElementFactory.source(jClass)
|
||||
)
|
||||
val valueParameters = if (isAnnotation) createAnnotationConstructorParameters(constructorDescriptor)
|
||||
else Collections.emptyList<ValueParameterDescriptor>()
|
||||
constructorDescriptor.setHasSynthesizedParameterNames(false)
|
||||
|
||||
constructorDescriptor.initialize(valueParameters, getConstructorVisibility(classDescriptor))
|
||||
constructorDescriptor.setHasStableParameterNames(true)
|
||||
constructorDescriptor.returnType = classDescriptor.defaultType
|
||||
c.components.javaResolverCache.recordConstructor(jClass, constructorDescriptor)
|
||||
return constructorDescriptor
|
||||
}
|
||||
|
||||
private fun getConstructorVisibility(classDescriptor: ClassDescriptor): Visibility {
|
||||
val visibility = classDescriptor.visibility
|
||||
if (visibility == JavaVisibilities.PROTECTED_STATIC_VISIBILITY) {
|
||||
return JavaVisibilities.PROTECTED_AND_PACKAGE
|
||||
}
|
||||
return visibility
|
||||
}
|
||||
|
||||
private fun createAnnotationConstructorParameters(constructor: ClassConstructorDescriptorImpl): List<ValueParameterDescriptor> {
|
||||
val methods = jClass.methods
|
||||
val result = ArrayList<ValueParameterDescriptor>(methods.size)
|
||||
|
||||
val attr = TypeUsage.COMMON.toAttributes(isForAnnotationParameter = true)
|
||||
|
||||
val (methodsNamedValue, otherMethods) = methods.
|
||||
partition { it.name == JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME }
|
||||
|
||||
assert(methodsNamedValue.size <= 1) { "There can't be more than one method named 'value' in annotation class: $jClass" }
|
||||
val methodNamedValue = methodsNamedValue.firstOrNull()
|
||||
if (methodNamedValue != null) {
|
||||
val parameterNamedValueJavaType = methodNamedValue.returnType
|
||||
val (parameterType, varargType) =
|
||||
if (parameterNamedValueJavaType is JavaArrayType)
|
||||
Pair(c.typeResolver.transformArrayType(parameterNamedValueJavaType, attr, isVararg = true),
|
||||
c.typeResolver.transformJavaType(parameterNamedValueJavaType.componentType, attr))
|
||||
else
|
||||
Pair(c.typeResolver.transformJavaType(parameterNamedValueJavaType, attr), null)
|
||||
|
||||
result.addAnnotationValueParameter(constructor, 0, methodNamedValue, parameterType, varargType)
|
||||
}
|
||||
|
||||
val startIndex = if (methodNamedValue != null) 1 else 0
|
||||
for ((index, method) in otherMethods.withIndex()) {
|
||||
val parameterType = c.typeResolver.transformJavaType(method.returnType, attr)
|
||||
result.addAnnotationValueParameter(constructor, index + startIndex, method, parameterType, null)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun MutableList<ValueParameterDescriptor>.addAnnotationValueParameter(
|
||||
constructor: ConstructorDescriptor,
|
||||
index: Int,
|
||||
method: JavaMethod,
|
||||
returnType: KotlinType,
|
||||
varargElementType: KotlinType?
|
||||
) {
|
||||
add(ValueParameterDescriptorImpl(
|
||||
constructor,
|
||||
null,
|
||||
index,
|
||||
Annotations.EMPTY,
|
||||
method.name,
|
||||
// Parameters of annotation constructors in Java are never nullable
|
||||
TypeUtils.makeNotNullable(returnType),
|
||||
method.hasAnnotationParameterDefaultValue,
|
||||
/* isCrossinline = */ false,
|
||||
/* isNoinline = */ false,
|
||||
// Nulls are not allowed in annotation arguments in Java
|
||||
varargElementType?.let { TypeUtils.makeNotNullable(it) },
|
||||
c.components.sourceElementFactory.source(method)
|
||||
))
|
||||
}
|
||||
|
||||
private val nestedClassIndex = c.storageManager.createLazyValue {
|
||||
jClass.innerClassNames.toSet()
|
||||
}
|
||||
|
||||
private val enumEntryIndex = c.storageManager.createLazyValue {
|
||||
jClass.fields.filter { it.isEnumEntry }.associateBy { f -> f.name }
|
||||
}
|
||||
|
||||
private val nestedClasses = c.storageManager.createMemoizedFunctionWithNullableValues {
|
||||
name: Name ->
|
||||
if (name !in nestedClassIndex()) {
|
||||
val field = enumEntryIndex()[name]
|
||||
if (field != null) {
|
||||
val enumMemberNames: NotNullLazyValue<Set<Name>> = c.storageManager.createLazyValue {
|
||||
getFunctionNames() + getVariableNames()
|
||||
}
|
||||
EnumEntrySyntheticClassDescriptor.create(
|
||||
c.storageManager, ownerDescriptor, name, enumMemberNames, c.resolveAnnotations(field),
|
||||
c.components.sourceElementFactory.source(field)
|
||||
)
|
||||
}
|
||||
else null
|
||||
}
|
||||
else {
|
||||
c.components.finder.findClass(ownerDescriptor.classId!!.createNestedClassId(name))?.let {
|
||||
LazyJavaClassDescriptor(c, ownerDescriptor, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDispatchReceiverParameter(): ReceiverParameterDescriptor? =
|
||||
DescriptorUtils.getDispatchReceiverParameterIfNeeded(ownerDescriptor)
|
||||
|
||||
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? {
|
||||
recordLookup(name, location)
|
||||
return nestedClasses(name)
|
||||
}
|
||||
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> {
|
||||
recordLookup(name, location)
|
||||
return super.getContributedFunctions(name, location)
|
||||
}
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
|
||||
recordLookup(name, location)
|
||||
return super.getContributedVariables(name, location)
|
||||
}
|
||||
|
||||
override fun computeClassNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set<Name>
|
||||
= nestedClassIndex() + enumEntryIndex().keys
|
||||
|
||||
override fun computePropertyNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set<Name> {
|
||||
if (jClass.isAnnotationType) return getFunctionNames()
|
||||
val result = LinkedHashSet(declaredMemberIndex().getFieldNames())
|
||||
return ownerDescriptor.typeConstructor.supertypes.flatMapTo(result) { supertype ->
|
||||
supertype.memberScope.getVariableNames()
|
||||
}
|
||||
}
|
||||
|
||||
override fun recordLookup(name: Name, location: LookupLocation) {
|
||||
c.components.lookupTracker.record(location, ownerDescriptor, name)
|
||||
}
|
||||
|
||||
override fun toString() = "Lazy Java member scope for " + jClass.fqName
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.lazy.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.lazy.childForClassOrPackage
|
||||
import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
|
||||
class LazyJavaPackageFragment(
|
||||
outerContext: LazyJavaResolverContext,
|
||||
private val jPackage: JavaPackage
|
||||
) : PackageFragmentDescriptorImpl(outerContext.module, jPackage.fqName) {
|
||||
private val c = outerContext.childForClassOrPackage(this)
|
||||
|
||||
internal val binaryClasses by c.storageManager.createLazyValue {
|
||||
c.components.packageMapper.findPackageParts(fqName.asString()).mapNotNull { partName ->
|
||||
val classId = ClassId.topLevel(JvmClassName.byInternalName(partName).fqNameForTopLevelClassMaybeWithDollars)
|
||||
c.components.kotlinClassFinder.findKotlinClass(classId)?.let { partName to it }
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
private val scope = JvmPackageScope(c, jPackage, this)
|
||||
|
||||
private val subPackages = c.storageManager.createRecursionTolerantLazyValue(
|
||||
{ jPackage.subPackages.map(JavaPackage::fqName) },
|
||||
// This breaks infinite recursion between loading Java descriptors and building light classes
|
||||
onRecursiveCall = listOf()
|
||||
)
|
||||
|
||||
override val annotations =
|
||||
// Do not resolve package annotations if JSR-305 is disabled
|
||||
if (c.components.annotationTypeQualifierResolver.disabled) Annotations.EMPTY
|
||||
else c.resolveAnnotations(jPackage)
|
||||
|
||||
internal fun getSubPackageFqNames(): List<FqName> = subPackages()
|
||||
|
||||
internal fun findClassifierByJavaClass(jClass: JavaClass): ClassDescriptor? = scope.javaScope.findClassifierByJavaClass(jClass)
|
||||
|
||||
private val partToFacade by c.storageManager.createLazyValue {
|
||||
val result = hashMapOf<JvmClassName, JvmClassName>()
|
||||
kotlinClasses@for ((partInternalName, kotlinClass) in binaryClasses) {
|
||||
val partName = JvmClassName.byInternalName(partInternalName)
|
||||
val header = kotlinClass.classHeader
|
||||
when (header.kind) {
|
||||
KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> {
|
||||
result[partName] = JvmClassName.byInternalName(header.multifileClassName ?: continue@kotlinClasses)
|
||||
}
|
||||
KotlinClassHeader.Kind.FILE_FACADE -> {
|
||||
result[partName] = partName
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fun getFacadeNameForPartName(partName: JvmClassName): JvmClassName? = partToFacade[partName]
|
||||
|
||||
override fun getMemberScope() = scope
|
||||
|
||||
override fun toString() = "Lazy Java package fragment: $fqName"
|
||||
|
||||
override fun getSource(): SourceElement = KotlinJvmBinaryPackageSourceElement(this)
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.lazy.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
||||
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.storage.NullableLazyValue
|
||||
import org.jetbrains.kotlin.utils.alwaysTrue
|
||||
import java.util.*
|
||||
|
||||
class LazyJavaPackageScope(
|
||||
c: LazyJavaResolverContext,
|
||||
private val jPackage: JavaPackage,
|
||||
override val ownerDescriptor: LazyJavaPackageFragment
|
||||
) : LazyJavaStaticScope(c) {
|
||||
// Null means that it's impossible to determine list of class names in package, i.e. in IDE where special finders exist
|
||||
// But for compiler though we can determine full list of class names by getting all class-file names in classpath and sources
|
||||
private val knownClassNamesInPackage: NullableLazyValue<Set<String>> = c.storageManager.createNullableLazyValue {
|
||||
c.components.finder.knownClassNamesInPackage(ownerDescriptor.fqName)
|
||||
}
|
||||
|
||||
private val classes = c.storageManager.createMemoizedFunctionWithNullableValues<FindClassRequest, ClassDescriptor> classByRequest@{ request ->
|
||||
val requestClassId = ClassId(ownerDescriptor.fqName, request.name)
|
||||
|
||||
val kotlinBinaryClass =
|
||||
// These branches should be semantically equal, but the first one could be faster
|
||||
if (request.javaClass != null)
|
||||
c.components.kotlinClassFinder.findKotlinClass(request.javaClass)
|
||||
else
|
||||
c.components.kotlinClassFinder.findKotlinClass(requestClassId)
|
||||
|
||||
val classId = kotlinBinaryClass?.classId
|
||||
// Nested/local classes can be found when running in CLI in case when request.name looks like 'Outer$Inner'
|
||||
// It happens because KotlinClassFinder searches through a file-based index that does not differ classes containing $-sign and nested ones
|
||||
if (classId != null && (classId.isNestedClass || classId.isLocal)) return@classByRequest null
|
||||
|
||||
val kotlinResult = resolveKotlinBinaryClass(kotlinBinaryClass)
|
||||
|
||||
when (kotlinResult) {
|
||||
is KotlinClassLookupResult.Found -> kotlinResult.descriptor
|
||||
is KotlinClassLookupResult.SyntheticClass -> null
|
||||
is KotlinClassLookupResult.NotFound -> {
|
||||
val javaClass = request.javaClass ?: c.components.finder.findClass(requestClassId)
|
||||
|
||||
if (javaClass?.lightClassOriginKind == LightClassOriginKind.BINARY) {
|
||||
throw IllegalStateException(
|
||||
"Couldn't find kotlin binary class for light class created by kotlin binary file\n" +
|
||||
"JavaClass: $javaClass\n" +
|
||||
"ClassId: $requestClassId\n" +
|
||||
"findKotlinClass(JavaClass) = ${c.components.kotlinClassFinder.findKotlinClass(javaClass)}\n" +
|
||||
"findKotlinClass(ClassId) = ${c.components.kotlinClassFinder.findKotlinClass(requestClassId)}\n"
|
||||
)
|
||||
}
|
||||
|
||||
val actualFqName = javaClass?.fqName
|
||||
if (actualFqName == null || actualFqName.isRoot || actualFqName.parent() != ownerDescriptor.fqName)
|
||||
null
|
||||
else
|
||||
LazyJavaClassDescriptor(c, ownerDescriptor, javaClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class KotlinClassLookupResult {
|
||||
class Found(val descriptor: ClassDescriptor) : KotlinClassLookupResult()
|
||||
object NotFound : KotlinClassLookupResult()
|
||||
object SyntheticClass : KotlinClassLookupResult()
|
||||
}
|
||||
|
||||
private fun resolveKotlinBinaryClass(kotlinClass: KotlinJvmBinaryClass?): KotlinClassLookupResult =
|
||||
when {
|
||||
kotlinClass == null -> {
|
||||
KotlinClassLookupResult.NotFound
|
||||
}
|
||||
kotlinClass.classHeader.kind == KotlinClassHeader.Kind.CLASS -> {
|
||||
val descriptor = c.components.deserializedDescriptorResolver.resolveClass(kotlinClass)
|
||||
if (descriptor != null) KotlinClassLookupResult.Found(descriptor) else KotlinClassLookupResult.NotFound
|
||||
}
|
||||
else -> {
|
||||
// This is a package or interface DefaultImpls or something like that
|
||||
KotlinClassLookupResult.SyntheticClass
|
||||
}
|
||||
}
|
||||
|
||||
// javaClass here is only for sake of optimizations
|
||||
private class FindClassRequest(val name: Name, val javaClass: JavaClass?) {
|
||||
override fun equals(other: Any?) = other is FindClassRequest && name == other.name
|
||||
|
||||
override fun hashCode() = name.hashCode()
|
||||
}
|
||||
|
||||
override fun getContributedClassifier(name: Name, location: LookupLocation) = findClassifier(name, null)
|
||||
|
||||
private fun findClassifier(name: Name, javaClass: JavaClass?): ClassDescriptor? {
|
||||
if (!SpecialNames.isSafeIdentifier(name)) return null
|
||||
|
||||
val knownClassNamesInPackage = knownClassNamesInPackage()
|
||||
if (javaClass == null && knownClassNamesInPackage != null && name.asString() !in knownClassNamesInPackage) {
|
||||
return null
|
||||
}
|
||||
|
||||
return classes(FindClassRequest(name, javaClass))
|
||||
}
|
||||
|
||||
internal fun findClassifierByJavaClass(javaClass: JavaClass) = findClassifier(javaClass.name, javaClass)
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> = emptyList()
|
||||
|
||||
override fun computeMemberIndex(): DeclaredMemberIndex = DeclaredMemberIndex.Empty
|
||||
|
||||
override fun computeClassNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set<Name> {
|
||||
// neither objects nor enum members can be in java package
|
||||
if (!kindFilter.acceptsKinds(DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS_MASK)) return emptySet()
|
||||
|
||||
val knownClassNamesInPackage = knownClassNamesInPackage()
|
||||
if (knownClassNamesInPackage != null) return knownClassNamesInPackage.mapTo(HashSet()) { Name.identifier(it) }
|
||||
|
||||
return jPackage.getClasses(nameFilter ?: alwaysTrue()).mapNotNullTo(linkedSetOf()) { klass ->
|
||||
if (klass.lightClassOriginKind == LightClassOriginKind.SOURCE) null else klass.name
|
||||
}
|
||||
}
|
||||
|
||||
override fun computeFunctionNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set<Name> {
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
override fun computeNonDeclaredFunctions(result: MutableCollection<SimpleFunctionDescriptor>, name: Name) {
|
||||
}
|
||||
|
||||
override fun computePropertyNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?) = emptySet<Name>()
|
||||
|
||||
// we don't use implementation from super which caches all descriptors and does not use filters
|
||||
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
|
||||
return computeDescriptors(kindFilter, nameFilter, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS)
|
||||
}
|
||||
}
|
||||
+368
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.lazy.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.lazy.childForMethod
|
||||
import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.toAttributes
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaArrayType
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaField
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgumentValue
|
||||
import org.jetbrains.kotlin.resolve.retainMostSpecificInEachOverridableGroup
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude.NonExtensions
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
||||
import org.jetbrains.kotlin.storage.NotNullLazyValue
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import java.util.*
|
||||
|
||||
abstract class LazyJavaScope(protected val c: LazyJavaResolverContext) : MemberScopeImpl() {
|
||||
protected abstract val ownerDescriptor: DeclarationDescriptor
|
||||
|
||||
// this lazy value is not used at all in LazyPackageFragmentScopeForJavaPackage because we do not use caching there
|
||||
// but is placed in the base class to not duplicate code
|
||||
private val allDescriptors = c.storageManager.createRecursionTolerantLazyValue<Collection<DeclarationDescriptor>>(
|
||||
{ computeDescriptors(DescriptorKindFilter.ALL, MemberScope.ALL_NAME_FILTER, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS) },
|
||||
// This is to avoid the following recursive case:
|
||||
// when computing getAllPackageNames() we ask the JavaPsiFacade for all subpackages of foo
|
||||
// it, in turn, asks JavaElementFinder for subpackages of Kotlin package foo, which calls getAllPackageNames() recursively
|
||||
// when on recursive call we return an empty collection, recursion collapses gracefully
|
||||
listOf()
|
||||
)
|
||||
|
||||
protected val declaredMemberIndex: NotNullLazyValue<DeclaredMemberIndex> = c.storageManager.createLazyValue { computeMemberIndex() }
|
||||
|
||||
protected abstract fun computeMemberIndex(): DeclaredMemberIndex
|
||||
|
||||
// Fake overrides, values()/valueOf(), etc.
|
||||
protected abstract fun computeNonDeclaredFunctions(result: MutableCollection<SimpleFunctionDescriptor>, name: Name)
|
||||
|
||||
protected abstract fun getDispatchReceiverParameter(): ReceiverParameterDescriptor?
|
||||
|
||||
private val functions = c.storageManager.createMemoizedFunction<Name, Collection<SimpleFunctionDescriptor>> {
|
||||
name ->
|
||||
val result = LinkedHashSet<SimpleFunctionDescriptor>()
|
||||
|
||||
for (method in declaredMemberIndex().findMethodsByName(name)) {
|
||||
val descriptor = resolveMethodToFunctionDescriptor(method)
|
||||
if (!descriptor.isVisibleAsFunction()) continue
|
||||
|
||||
c.components.javaResolverCache.recordMethod(method, descriptor)
|
||||
result.add(descriptor)
|
||||
}
|
||||
|
||||
result.retainMostSpecificInEachOverridableGroup()
|
||||
|
||||
computeNonDeclaredFunctions(result, name)
|
||||
|
||||
c.components.signatureEnhancement.enhanceSignatures(c, result).toList()
|
||||
}
|
||||
|
||||
open protected fun JavaMethodDescriptor.isVisibleAsFunction() = true
|
||||
|
||||
protected data class MethodSignatureData(
|
||||
val returnType: KotlinType,
|
||||
val receiverType: KotlinType?,
|
||||
val valueParameters: List<ValueParameterDescriptor>,
|
||||
val typeParameters: List<TypeParameterDescriptor>,
|
||||
val hasStableParameterNames: Boolean,
|
||||
val errors: List<String>
|
||||
)
|
||||
|
||||
protected abstract fun resolveMethodSignature(
|
||||
method: JavaMethod,
|
||||
methodTypeParameters: List<TypeParameterDescriptor>,
|
||||
returnType: KotlinType,
|
||||
valueParameters: List<ValueParameterDescriptor>
|
||||
): MethodSignatureData
|
||||
|
||||
protected fun resolveMethodToFunctionDescriptor(method: JavaMethod): JavaMethodDescriptor {
|
||||
val annotations = c.resolveAnnotations(method)
|
||||
val functionDescriptorImpl = JavaMethodDescriptor.createJavaMethod(
|
||||
ownerDescriptor, annotations, method.name, c.components.sourceElementFactory.source(method)
|
||||
)
|
||||
|
||||
val c = c.childForMethod(functionDescriptorImpl, method)
|
||||
|
||||
val methodTypeParameters = method.typeParameters.map { p -> c.typeParameterResolver.resolveTypeParameter(p)!! }
|
||||
val valueParameters = resolveValueParameters(c, functionDescriptorImpl, method.valueParameters)
|
||||
|
||||
val returnType = computeMethodReturnType(method, c)
|
||||
|
||||
val effectiveSignature = resolveMethodSignature(method, methodTypeParameters, returnType, valueParameters.descriptors)
|
||||
|
||||
functionDescriptorImpl.initialize(
|
||||
effectiveSignature.receiverType,
|
||||
getDispatchReceiverParameter(),
|
||||
effectiveSignature.typeParameters,
|
||||
effectiveSignature.valueParameters,
|
||||
effectiveSignature.returnType,
|
||||
Modality.convertFromFlags(method.isAbstract, !method.isFinal),
|
||||
method.visibility,
|
||||
if (effectiveSignature.receiverType != null)
|
||||
mapOf(JavaMethodDescriptor.ORIGINAL_VALUE_PARAMETER_FOR_EXTENSION_RECEIVER to valueParameters.descriptors.first())
|
||||
else
|
||||
emptyMap<FunctionDescriptor.UserDataKey<ValueParameterDescriptor>, ValueParameterDescriptor>()
|
||||
)
|
||||
|
||||
functionDescriptorImpl.setParameterNamesStatus(effectiveSignature.hasStableParameterNames, valueParameters.hasSynthesizedNames)
|
||||
|
||||
if (effectiveSignature.errors.isNotEmpty()) {
|
||||
c.components.signaturePropagator.reportSignatureErrors(functionDescriptorImpl, effectiveSignature.errors)
|
||||
}
|
||||
|
||||
return functionDescriptorImpl
|
||||
}
|
||||
|
||||
protected fun computeMethodReturnType(method: JavaMethod, c: LazyJavaResolverContext): KotlinType {
|
||||
val annotationMethod = method.containingClass.isAnnotationType
|
||||
val returnTypeAttrs = TypeUsage.COMMON.toAttributes(
|
||||
isForAnnotationParameter = annotationMethod
|
||||
)
|
||||
return c.typeResolver.transformJavaType(method.returnType, returnTypeAttrs)
|
||||
}
|
||||
|
||||
protected class ResolvedValueParameters(val descriptors: List<ValueParameterDescriptor>, val hasSynthesizedNames: Boolean)
|
||||
|
||||
protected fun resolveValueParameters(
|
||||
c: LazyJavaResolverContext,
|
||||
function: FunctionDescriptor,
|
||||
jValueParameters: List<JavaValueParameter>
|
||||
): ResolvedValueParameters {
|
||||
var synthesizedNames = false
|
||||
val usedNames = mutableSetOf<String>()
|
||||
|
||||
val descriptors = jValueParameters.withIndex().map { (index, javaParameter) ->
|
||||
val annotations = c.resolveAnnotations(javaParameter)
|
||||
val typeUsage = TypeUsage.COMMON.toAttributes()
|
||||
val parameterName = annotations
|
||||
.findAnnotation(JvmAnnotationNames.PARAMETER_NAME_FQ_NAME)
|
||||
?.firstArgumentValue()
|
||||
?.safeAs<String>()
|
||||
|
||||
val (outType, varargElementType) =
|
||||
if (javaParameter.isVararg) {
|
||||
val paramType = javaParameter.type as? JavaArrayType
|
||||
?: throw AssertionError("Vararg parameter should be an array: $javaParameter")
|
||||
val outType = c.typeResolver.transformArrayType(paramType, typeUsage, true)
|
||||
outType to c.module.builtIns.getArrayElementType(outType)
|
||||
}
|
||||
else {
|
||||
c.typeResolver.transformJavaType(javaParameter.type, typeUsage) to null
|
||||
}
|
||||
|
||||
val name = if (function.name.asString() == "equals" &&
|
||||
jValueParameters.size == 1 &&
|
||||
c.module.builtIns.nullableAnyType == outType) {
|
||||
// This is a hack to prevent numerous warnings on Kotlin classes that inherit Java classes: if you override "equals" in such
|
||||
// class without this hack, you'll be warned that in the superclass the name is "p0" (regardless of the fact that it's
|
||||
// "other" in Any)
|
||||
// TODO: fix Java parameter name loading logic somehow (don't always load "p0", "p1", etc.)
|
||||
Name.identifier("other")
|
||||
}
|
||||
else if (parameterName != null && parameterName.isNotEmpty() && usedNames.add(parameterName)) {
|
||||
Name.identifier(parameterName)
|
||||
}
|
||||
else {
|
||||
// TODO: parameter names may be drawn from attached sources, which is slow; it's better to make them lazy
|
||||
val javaName = javaParameter.name
|
||||
if (javaName == null) synthesizedNames = true
|
||||
javaName ?: Name.identifier("p$index")
|
||||
}
|
||||
|
||||
ValueParameterDescriptorImpl(
|
||||
function,
|
||||
null,
|
||||
index,
|
||||
annotations,
|
||||
name,
|
||||
outType,
|
||||
/* declaresDefaultValue = */ false,
|
||||
/* isCrossinline = */ false,
|
||||
/* isNoinline = */ false,
|
||||
varargElementType,
|
||||
c.components.sourceElementFactory.source(javaParameter)
|
||||
)
|
||||
}.toList()
|
||||
return ResolvedValueParameters(descriptors, synthesizedNames)
|
||||
}
|
||||
|
||||
private val functionNamesLazy by c.storageManager.createLazyValue { computeFunctionNames(DescriptorKindFilter.FUNCTIONS, null) }
|
||||
private val propertyNamesLazy by c.storageManager.createLazyValue { computePropertyNames(DescriptorKindFilter.VARIABLES, null) }
|
||||
private val classNamesLazy by c.storageManager.createLazyValue { computeClassNames(DescriptorKindFilter.CLASSIFIERS, null) }
|
||||
|
||||
override fun getFunctionNames() = functionNamesLazy
|
||||
override fun getVariableNames() = propertyNamesLazy
|
||||
override fun getClassifierNames() = classNamesLazy
|
||||
|
||||
override fun definitelyDoesNotContainName(name: Name): Boolean {
|
||||
return name !in functionNamesLazy && name !in propertyNamesLazy && name !in classNamesLazy
|
||||
}
|
||||
|
||||
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> {
|
||||
if (name !in getFunctionNames()) return emptyList()
|
||||
return functions(name)
|
||||
}
|
||||
|
||||
protected abstract fun computeFunctionNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set<Name>
|
||||
|
||||
protected abstract fun computeNonDeclaredProperties(name: Name, result: MutableCollection<PropertyDescriptor>)
|
||||
|
||||
protected abstract fun computePropertyNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set<Name>
|
||||
|
||||
private val properties = c.storageManager.createMemoizedFunction {
|
||||
name: Name ->
|
||||
val properties = ArrayList<PropertyDescriptor>()
|
||||
|
||||
val field = declaredMemberIndex().findFieldByName(name)
|
||||
if (field != null && !field.isEnumEntry) {
|
||||
properties.add(resolveProperty(field))
|
||||
}
|
||||
|
||||
computeNonDeclaredProperties(name, properties)
|
||||
|
||||
if (DescriptorUtils.isAnnotationClass(ownerDescriptor))
|
||||
properties.toList()
|
||||
else
|
||||
c.components.signatureEnhancement.enhanceSignatures(c, properties).toList()
|
||||
}
|
||||
|
||||
private fun resolveProperty(field: JavaField): PropertyDescriptor {
|
||||
val propertyDescriptor = createPropertyDescriptor(field)
|
||||
propertyDescriptor.initialize(null, null)
|
||||
|
||||
val propertyType = getPropertyType(field)
|
||||
|
||||
propertyDescriptor.setType(propertyType, listOf(), getDispatchReceiverParameter(), null as KotlinType?)
|
||||
|
||||
if (DescriptorUtils.shouldRecordInitializerForProperty(propertyDescriptor, propertyDescriptor.type)) {
|
||||
propertyDescriptor.setCompileTimeInitializer(
|
||||
c.storageManager.createNullableLazyValue {
|
||||
c.components.javaPropertyInitializerEvaluator.getInitializerConstant(field, propertyDescriptor)
|
||||
})
|
||||
}
|
||||
|
||||
c.components.javaResolverCache.recordField(field, propertyDescriptor)
|
||||
|
||||
return propertyDescriptor
|
||||
}
|
||||
|
||||
private fun createPropertyDescriptor(field: JavaField): PropertyDescriptorImpl {
|
||||
val isVar = !field.isFinal
|
||||
val annotations = c.resolveAnnotations(field)
|
||||
|
||||
return JavaPropertyDescriptor.create(
|
||||
ownerDescriptor, annotations, Modality.FINAL, field.visibility, isVar, field.name,
|
||||
c.components.sourceElementFactory.source(field), /* isConst = */ field.isFinalStatic
|
||||
)
|
||||
}
|
||||
|
||||
private val JavaField.isFinalStatic: Boolean
|
||||
get() = isFinal && isStatic
|
||||
|
||||
private fun getPropertyType(field: JavaField): KotlinType {
|
||||
// Fields do not have their own generic parameters.
|
||||
// Simple static constants should not have flexible types.
|
||||
val isNotNullable = !(field.isFinalStatic && field.hasConstantNotNullInitializer)
|
||||
val propertyType = c.typeResolver.transformJavaType(
|
||||
field.type,
|
||||
TypeUsage.COMMON.toAttributes()
|
||||
)
|
||||
if (!isNotNullable) {
|
||||
return TypeUtils.makeNotNullable(propertyType)
|
||||
}
|
||||
|
||||
return propertyType
|
||||
}
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
|
||||
if (name !in getVariableNames()) return emptyList()
|
||||
return properties(name)
|
||||
}
|
||||
|
||||
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = allDescriptors()
|
||||
|
||||
protected fun computeDescriptors(
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean,
|
||||
location: LookupLocation
|
||||
): List<DeclarationDescriptor> {
|
||||
val result = LinkedHashSet<DeclarationDescriptor>()
|
||||
|
||||
if (kindFilter.acceptsKinds(DescriptorKindFilter.CLASSIFIERS_MASK)) {
|
||||
for (name in computeClassNames(kindFilter, nameFilter)) {
|
||||
if (nameFilter(name)) {
|
||||
// Null signifies that a class found in Java is not present in Kotlin (e.g. package class)
|
||||
result.addIfNotNull(getContributedClassifier(name, location))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (kindFilter.acceptsKinds(DescriptorKindFilter.FUNCTIONS_MASK) && !kindFilter.excludes.contains(NonExtensions)) {
|
||||
for (name in computeFunctionNames(kindFilter, nameFilter)) {
|
||||
if (nameFilter(name)) {
|
||||
result.addAll(getContributedFunctions(name, location))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (kindFilter.acceptsKinds(DescriptorKindFilter.VARIABLES_MASK) && !kindFilter.excludes.contains(NonExtensions)) {
|
||||
for (name in computePropertyNames(kindFilter, nameFilter)) {
|
||||
if (nameFilter(name)) {
|
||||
result.addAll(getContributedVariables(name, location))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.toList()
|
||||
}
|
||||
|
||||
protected abstract fun computeClassNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set<Name>
|
||||
|
||||
override fun toString() = "Lazy scope for $ownerDescriptor"
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.println(this::class.java.simpleName, " {")
|
||||
p.pushIndent()
|
||||
|
||||
p.println("containingDeclaration: $ownerDescriptor")
|
||||
|
||||
p.popIndent()
|
||||
p.println("}")
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.lazy.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils.resolveOverridesForStaticMembers
|
||||
import org.jetbrains.kotlin.load.java.descriptors.getParentJavaStaticClassScope
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory.createEnumValueOfMethod
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory.createEnumValuesMethod
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
|
||||
class LazyJavaStaticClassScope(
|
||||
c: LazyJavaResolverContext,
|
||||
private val jClass: JavaClass,
|
||||
override val ownerDescriptor: LazyJavaClassDescriptor
|
||||
) : LazyJavaStaticScope(c) {
|
||||
|
||||
override fun computeMemberIndex() = ClassDeclaredMemberIndex(jClass) { it.isStatic }
|
||||
|
||||
override fun computeFunctionNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?) =
|
||||
declaredMemberIndex().getMethodNames().toMutableSet().apply {
|
||||
addAll(ownerDescriptor.getParentJavaStaticClassScope()?.getFunctionNames().orEmpty())
|
||||
if (jClass.isEnum) {
|
||||
addAll(listOf(DescriptorUtils.ENUM_VALUE_OF, DescriptorUtils.ENUM_VALUES))
|
||||
}
|
||||
}
|
||||
|
||||
override fun computePropertyNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?) =
|
||||
declaredMemberIndex().getFieldNames().toMutableSet().apply {
|
||||
flatMapJavaStaticSupertypesScopes(ownerDescriptor, this) { it.getVariableNames() }
|
||||
}
|
||||
|
||||
override fun computeClassNames(kindFilter: DescriptorKindFilter, nameFilter: ((Name) -> Boolean)?): Set<Name> = emptySet()
|
||||
|
||||
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? {
|
||||
// We don't need to track lookups here because we find nested/inner classes in LazyJavaClassMemberScope
|
||||
return null
|
||||
}
|
||||
|
||||
override fun computeNonDeclaredFunctions(result: MutableCollection<SimpleFunctionDescriptor>, name: Name) {
|
||||
val functionsFromSupertypes = getStaticFunctionsFromJavaSuperClasses(name, ownerDescriptor)
|
||||
result.addAll(resolveOverridesForStaticMembers(name, functionsFromSupertypes, result, ownerDescriptor, c.components.errorReporter))
|
||||
|
||||
if (jClass.isEnum) {
|
||||
when (name) {
|
||||
DescriptorUtils.ENUM_VALUE_OF -> result.add(createEnumValueOfMethod(ownerDescriptor))
|
||||
DescriptorUtils.ENUM_VALUES -> result.add(createEnumValuesMethod(ownerDescriptor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun computeNonDeclaredProperties(name: Name, result: MutableCollection<PropertyDescriptor>) {
|
||||
val propertiesFromSupertypes = flatMapJavaStaticSupertypesScopes(ownerDescriptor, mutableSetOf()) {
|
||||
it.getContributedVariables(name, NoLookupLocation.WHEN_GET_SUPER_MEMBERS)
|
||||
}
|
||||
|
||||
if (result.isNotEmpty()) {
|
||||
result.addAll(resolveOverridesForStaticMembers(
|
||||
name, propertiesFromSupertypes, result, ownerDescriptor, c.components.errorReporter
|
||||
))
|
||||
}
|
||||
else {
|
||||
result.addAll(propertiesFromSupertypes.groupBy {
|
||||
it.realOriginal
|
||||
}.flatMap {
|
||||
resolveOverridesForStaticMembers(name, it.value, result, ownerDescriptor, c.components.errorReporter)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun getStaticFunctionsFromJavaSuperClasses(name: Name, descriptor: ClassDescriptor): Set<SimpleFunctionDescriptor> {
|
||||
val staticScope = descriptor.getParentJavaStaticClassScope() ?: return emptySet()
|
||||
return staticScope.getContributedFunctions(name, NoLookupLocation.WHEN_GET_SUPER_MEMBERS).toSet()
|
||||
}
|
||||
|
||||
private fun <R> flatMapJavaStaticSupertypesScopes(
|
||||
root: ClassDescriptor,
|
||||
result: MutableSet<R>,
|
||||
onJavaStaticScope: (MemberScope) -> Collection<R>
|
||||
): Set<R> {
|
||||
DFS.dfs(listOf(root),
|
||||
{
|
||||
it.typeConstructor.supertypes.asSequence().mapNotNull {
|
||||
supertype -> supertype.constructor.declarationDescriptor as? ClassDescriptor
|
||||
}.asIterable()
|
||||
},
|
||||
object : DFS.AbstractNodeHandler<ClassDescriptor, Unit>() {
|
||||
override fun beforeChildren(current: ClassDescriptor): Boolean {
|
||||
if (current === root) return true
|
||||
val staticScope = current.staticScope
|
||||
|
||||
if (staticScope is LazyJavaStaticScope) {
|
||||
result.addAll(onJavaStaticScope(staticScope))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun result() {}
|
||||
}
|
||||
)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private val PropertyDescriptor.realOriginal: PropertyDescriptor
|
||||
get() {
|
||||
if (this.kind.isReal) return this
|
||||
|
||||
return this.overriddenDescriptors.map { it.realOriginal }.distinct().single()
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.lazy.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
abstract class LazyJavaStaticScope(c: LazyJavaResolverContext) : LazyJavaScope(c) {
|
||||
override fun getDispatchReceiverParameter() = null
|
||||
|
||||
override fun resolveMethodSignature(
|
||||
method: JavaMethod, methodTypeParameters: List<TypeParameterDescriptor>, returnType: KotlinType,
|
||||
valueParameters: List<ValueParameterDescriptor>
|
||||
) = LazyJavaScope.MethodSignatureData(returnType, null, valueParameters, methodTypeParameters, false, emptyList())
|
||||
|
||||
override fun computeNonDeclaredProperties(name: Name, result: MutableCollection<PropertyDescriptor>) {
|
||||
//no undeclared properties
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.lazy.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.descriptors.impl.AbstractLazyTypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaAnnotations
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.toAttributes
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
class LazyJavaTypeParameterDescriptor(
|
||||
private val c: LazyJavaResolverContext,
|
||||
val javaTypeParameter: JavaTypeParameter,
|
||||
index: Int,
|
||||
containingDeclaration: DeclarationDescriptor
|
||||
) : AbstractLazyTypeParameterDescriptor(
|
||||
c.storageManager,
|
||||
containingDeclaration,
|
||||
javaTypeParameter.name,
|
||||
Variance.INVARIANT,
|
||||
/* isReified = */ false,
|
||||
index,
|
||||
SourceElement.NO_SOURCE, c.components.supertypeLoopChecker
|
||||
) {
|
||||
override val annotations = LazyJavaAnnotations(c, javaTypeParameter)
|
||||
|
||||
override fun resolveUpperBounds(): List<KotlinType> {
|
||||
val bounds = javaTypeParameter.upperBounds
|
||||
if (bounds.isEmpty()) {
|
||||
return listOf(KotlinTypeFactory.flexibleType(
|
||||
c.module.builtIns.anyType,
|
||||
c.module.builtIns.nullableAnyType
|
||||
))
|
||||
}
|
||||
return bounds.map {
|
||||
c.typeResolver.transformJavaType(it, TypeUsage.COMMON.toAttributes(upperBoundForTypeParameter = this))
|
||||
}
|
||||
}
|
||||
|
||||
override fun reportSupertypeLoopError(type: KotlinType) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.lazy
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaTypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameterListOwner
|
||||
import org.jetbrains.kotlin.utils.mapToIndex
|
||||
|
||||
interface TypeParameterResolver {
|
||||
object EMPTY : TypeParameterResolver {
|
||||
override fun resolveTypeParameter(javaTypeParameter: JavaTypeParameter): TypeParameterDescriptor? = null
|
||||
}
|
||||
|
||||
fun resolveTypeParameter(javaTypeParameter: JavaTypeParameter): TypeParameterDescriptor?
|
||||
}
|
||||
|
||||
class LazyJavaTypeParameterResolver(
|
||||
private val c: LazyJavaResolverContext,
|
||||
private val containingDeclaration: DeclarationDescriptor,
|
||||
typeParameterOwner: JavaTypeParameterListOwner,
|
||||
private val typeParametersIndexOffset: Int
|
||||
) : TypeParameterResolver {
|
||||
private val typeParameters: Map<JavaTypeParameter, Int> = typeParameterOwner.typeParameters.mapToIndex()
|
||||
|
||||
private val resolve = c.storageManager.createMemoizedFunctionWithNullableValues {
|
||||
typeParameter: JavaTypeParameter ->
|
||||
typeParameters[typeParameter]?.let { index ->
|
||||
LazyJavaTypeParameterDescriptor(c.child(this), typeParameter, typeParametersIndexOffset + index, containingDeclaration)
|
||||
}
|
||||
}
|
||||
|
||||
override fun resolveTypeParameter(javaTypeParameter: JavaTypeParameter): TypeParameterDescriptor? {
|
||||
return resolve(javaTypeParameter) ?: c.typeParameterResolver.resolveTypeParameter(javaTypeParameter)
|
||||
}
|
||||
}
|
||||
+352
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.lazy.types
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage.COMMON
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage.SUPERTYPE
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaAnnotations
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.lazy.TypeParameterResolver
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeFlexibility.*
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.Variance.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.createProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
|
||||
private val JAVA_LANG_CLASS_FQ_NAME: FqName = FqName("java.lang.Class")
|
||||
|
||||
class JavaTypeResolver(
|
||||
private val c: LazyJavaResolverContext,
|
||||
private val typeParameterResolver: TypeParameterResolver
|
||||
) {
|
||||
|
||||
fun transformJavaType(javaType: JavaType, attr: JavaTypeAttributes): KotlinType {
|
||||
return when (javaType) {
|
||||
is JavaPrimitiveType -> {
|
||||
val primitiveType = javaType.type
|
||||
if (primitiveType != null) c.module.builtIns.getPrimitiveKotlinType(primitiveType)
|
||||
else c.module.builtIns.unitType
|
||||
}
|
||||
is JavaClassifierType -> transformJavaClassifierType(javaType, attr)
|
||||
is JavaArrayType -> transformArrayType(javaType, attr)
|
||||
// Top level type can be a wildcard only in case of broken Java code, but we should not fail with exceptions in such cases
|
||||
is JavaWildcardType -> javaType.bound?.let { transformJavaType(it, attr) } ?: c.module.builtIns.defaultBound
|
||||
else -> throw UnsupportedOperationException("Unsupported type: " + javaType)
|
||||
}
|
||||
}
|
||||
|
||||
fun transformArrayType(arrayType: JavaArrayType, attr: JavaTypeAttributes, isVararg: Boolean = false): KotlinType {
|
||||
val javaComponentType = arrayType.componentType
|
||||
val primitiveType = (javaComponentType as? JavaPrimitiveType)?.type
|
||||
if (primitiveType != null) {
|
||||
val jetType = c.module.builtIns.getPrimitiveArrayKotlinType(primitiveType)
|
||||
return if (attr.isForAnnotationParameter)
|
||||
jetType
|
||||
else KotlinTypeFactory.flexibleType(jetType, jetType.makeNullableAsSpecified(true))
|
||||
}
|
||||
|
||||
val componentType = transformJavaType(javaComponentType,
|
||||
COMMON.toAttributes(attr.isForAnnotationParameter))
|
||||
|
||||
if (attr.isForAnnotationParameter) {
|
||||
val projectionKind = if (isVararg) OUT_VARIANCE else INVARIANT
|
||||
return c.module.builtIns.getArrayType(projectionKind, componentType)
|
||||
}
|
||||
|
||||
return KotlinTypeFactory.flexibleType(
|
||||
c.module.builtIns.getArrayType(INVARIANT, componentType),
|
||||
c.module.builtIns.getArrayType(OUT_VARIANCE, componentType).makeNullableAsSpecified(true)
|
||||
)
|
||||
}
|
||||
|
||||
private fun transformJavaClassifierType(javaType: JavaClassifierType, attr: JavaTypeAttributes): KotlinType {
|
||||
fun errorType() = ErrorUtils.createErrorType("Unresolved java class ${javaType.presentableText}")
|
||||
|
||||
val useFlexible = !attr.isForAnnotationParameter && attr.howThisTypeIsUsed != SUPERTYPE
|
||||
val isRaw = javaType.isRaw
|
||||
if (!isRaw && !useFlexible) {
|
||||
return computeSimpleJavaClassifierType(javaType, attr, null) ?: errorType()
|
||||
}
|
||||
|
||||
val lower =
|
||||
computeSimpleJavaClassifierType(javaType, attr.withFlexibility(FLEXIBLE_LOWER_BOUND), lowerResult = null)
|
||||
?: return errorType()
|
||||
val upper =
|
||||
computeSimpleJavaClassifierType(javaType, attr.withFlexibility(FLEXIBLE_UPPER_BOUND), lowerResult = lower)
|
||||
?: return errorType()
|
||||
|
||||
return if (isRaw) {
|
||||
RawTypeImpl(lower, upper)
|
||||
}
|
||||
else {
|
||||
KotlinTypeFactory.flexibleType(lower, upper)
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeSimpleJavaClassifierType(
|
||||
javaType: JavaClassifierType, attr: JavaTypeAttributes,
|
||||
lowerResult: SimpleType?
|
||||
): SimpleType? {
|
||||
val annotations =
|
||||
lowerResult?.annotations ?: LazyJavaAnnotations(c, javaType)
|
||||
val constructor = computeTypeConstructor(javaType, attr) ?: return null
|
||||
val isNullable = attr.isNullable()
|
||||
|
||||
if (lowerResult?.constructor == constructor && !javaType.isRaw && isNullable) {
|
||||
return lowerResult.makeNullableAsSpecified(true)
|
||||
}
|
||||
|
||||
val arguments = computeArguments(javaType, attr, constructor)
|
||||
|
||||
return KotlinTypeFactory.simpleType(annotations, constructor, arguments, isNullable)
|
||||
}
|
||||
|
||||
private fun computeTypeConstructor(javaType: JavaClassifierType, attr: JavaTypeAttributes): TypeConstructor? {
|
||||
val classifier = javaType.classifier ?: return createNotFoundClass(javaType)
|
||||
return when (classifier) {
|
||||
is JavaClass -> {
|
||||
val fqName = classifier.fqName.sure { "Class type should have a FQ name: $classifier" }
|
||||
|
||||
val classData = mapKotlinClass(javaType, attr, fqName) ?: c.components.moduleClassResolver.resolveClass(classifier)
|
||||
classData?.typeConstructor ?: createNotFoundClass(javaType)
|
||||
}
|
||||
is JavaTypeParameter -> {
|
||||
typeParameterResolver.resolveTypeParameter(classifier)?.typeConstructor
|
||||
}
|
||||
else -> throw IllegalStateException("Unknown classifier kind: $classifier")
|
||||
}
|
||||
}
|
||||
|
||||
// There's no way to extract precise type information in PSI when the type's classifier cannot be resolved.
|
||||
// So we just take the canonical text of the type (which seems to be the only option at the moment), erase all type arguments
|
||||
// and treat the resulting qualified name as if it references a simple top-level class.
|
||||
// Note that this makes MISSING_DEPENDENCY_CLASS diagnostic messages not as precise as they could be in some corner cases.
|
||||
private fun createNotFoundClass(javaType: JavaClassifierType): TypeConstructor {
|
||||
val classId = ClassId.topLevel(FqName(javaType.classifierQualifiedName))
|
||||
return c.components.deserializedDescriptorResolver.components.notFoundClasses.getClass(classId, listOf(0)).typeConstructor
|
||||
}
|
||||
|
||||
private fun mapKotlinClass(javaType: JavaClassifierType, attr: JavaTypeAttributes, fqName: FqName): ClassDescriptor? {
|
||||
if (attr.isForAnnotationParameter && fqName == JAVA_LANG_CLASS_FQ_NAME) {
|
||||
return c.components.reflectionTypes.kClass
|
||||
}
|
||||
|
||||
val javaToKotlin = JavaToKotlinClassMap
|
||||
|
||||
val kotlinDescriptor = javaToKotlin.mapJavaToKotlin(fqName, c.module.builtIns) ?: return null
|
||||
|
||||
if (javaToKotlin.isReadOnly(kotlinDescriptor)) {
|
||||
if (attr.flexibility == FLEXIBLE_LOWER_BOUND ||
|
||||
attr.howThisTypeIsUsed == SUPERTYPE ||
|
||||
javaType.argumentsMakeSenseOnlyForMutableContainer(readOnlyContainer = kotlinDescriptor)) {
|
||||
return javaToKotlin.convertReadOnlyToMutable(kotlinDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
return kotlinDescriptor
|
||||
}
|
||||
|
||||
// Returns true for covariant read-only container that has mutable pair with invariant parameter
|
||||
// List<in A> does not make sense, but MutableList<in A> does
|
||||
// Same for Map<K, in V>
|
||||
// But both Iterable<in A>, MutableIterable<in A> don't make sense as they are covariant, so return false
|
||||
private fun JavaClassifierType.argumentsMakeSenseOnlyForMutableContainer(
|
||||
readOnlyContainer: ClassDescriptor
|
||||
): Boolean {
|
||||
fun JavaType?.isSuperWildcard(): Boolean = (this as? JavaWildcardType)?.let { it.bound != null && !it.isExtends } ?: false
|
||||
|
||||
if (!typeArguments.lastOrNull().isSuperWildcard()) return false
|
||||
val mutableLastParameterVariance = JavaToKotlinClassMap.convertReadOnlyToMutable(readOnlyContainer)
|
||||
.typeConstructor.parameters.lastOrNull()?.variance ?: return false
|
||||
|
||||
return mutableLastParameterVariance != OUT_VARIANCE
|
||||
}
|
||||
|
||||
private fun computeArguments(
|
||||
javaType: JavaClassifierType,
|
||||
attr: JavaTypeAttributes,
|
||||
constructor: TypeConstructor
|
||||
): List<TypeProjection> {
|
||||
val isRaw = javaType.isRaw
|
||||
val eraseTypeParameters =
|
||||
isRaw ||
|
||||
// This option is needed because sometimes we get weird versions of JDK classes in the class path,
|
||||
// such as collections with no generics, so the Java types are not raw, formally, but they don't match with
|
||||
// their Kotlin analogs, so we treat them as raw to avoid exceptions
|
||||
(javaType.typeArguments.isEmpty() && !constructor.parameters.isEmpty())
|
||||
|
||||
val typeParameters = constructor.parameters
|
||||
if (eraseTypeParameters) {
|
||||
return typeParameters.map {
|
||||
parameter ->
|
||||
// Some activity for preventing recursion in cases like `class A<T extends A, F extends T>`
|
||||
//
|
||||
// When calculating upper bound of some parameter (attr.upperBoundOfTypeParameter),
|
||||
// do not try to start upper bound calculation of it again.
|
||||
// If we met such recursive dependency it means that upper bound of `attr.upperBoundOfTypeParameter` based effectively
|
||||
// on the current class, so we can manually erase default type of current constructor.
|
||||
//
|
||||
// In example above corner cases are:
|
||||
// - Calculating first argument for raw upper bound of T. It depends on T, so we just get A<*, *>
|
||||
// - Calculating second argument for raw upper bound of T. It depends on F, that again depends on upper bound of T,
|
||||
// so we get A<*, *>.
|
||||
// Summary result for upper bound of T is `A<A<*, *>, A<*, *>>..A<out A<*, *>, out A<*, *>>`
|
||||
val erasedUpperBound =
|
||||
LazyWrappedType(c.storageManager) {
|
||||
parameter.getErasedUpperBound(attr.upperBoundOfTypeParameter) {
|
||||
constructor.declarationDescriptor!!.defaultType.replaceArgumentsWithStarProjections()
|
||||
}
|
||||
}
|
||||
|
||||
RawSubstitution.computeProjection(
|
||||
parameter,
|
||||
// if erasure happens due to invalid arguments number, use star projections instead
|
||||
if (isRaw) attr else attr.withFlexibility(INFLEXIBLE),
|
||||
erasedUpperBound
|
||||
)
|
||||
}.toList()
|
||||
}
|
||||
|
||||
if (typeParameters.size != javaType.typeArguments.size) {
|
||||
// Most of the time this means there is an error in the Java code
|
||||
return typeParameters.map { p -> TypeProjectionImpl(ErrorUtils.createErrorType(p.name.asString())) }.toList()
|
||||
}
|
||||
return javaType.typeArguments.withIndex().map {
|
||||
indexedArgument ->
|
||||
val (i, javaTypeArgument) = indexedArgument
|
||||
|
||||
assert(i < typeParameters.size) {
|
||||
"Argument index should be less then type parameters count, but $i > ${typeParameters.size}"
|
||||
}
|
||||
|
||||
val parameter = typeParameters[i]
|
||||
transformToTypeProjection(javaTypeArgument, COMMON.toAttributes(), parameter)
|
||||
}.toList()
|
||||
}
|
||||
|
||||
private fun transformToTypeProjection(
|
||||
javaType: JavaType,
|
||||
attr: JavaTypeAttributes,
|
||||
typeParameter: TypeParameterDescriptor
|
||||
): TypeProjection {
|
||||
return when (javaType) {
|
||||
is JavaWildcardType -> {
|
||||
val bound = javaType.bound
|
||||
val projectionKind = if (javaType.isExtends) OUT_VARIANCE else IN_VARIANCE
|
||||
if (bound == null || projectionKind.isConflictingArgumentFor(typeParameter))
|
||||
makeStarProjection(typeParameter, attr)
|
||||
else {
|
||||
createProjection(
|
||||
type = transformJavaType(bound, COMMON.toAttributes()),
|
||||
projectionKind = projectionKind,
|
||||
typeParameterDescriptor = typeParameter
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> TypeProjectionImpl(INVARIANT, transformJavaType(javaType, attr))
|
||||
}
|
||||
}
|
||||
|
||||
private fun Variance.isConflictingArgumentFor(typeParameter: TypeParameterDescriptor): Boolean {
|
||||
if (typeParameter.variance == INVARIANT) return false
|
||||
return this != typeParameter.variance
|
||||
}
|
||||
|
||||
private fun JavaTypeAttributes.isNullable(): Boolean {
|
||||
if (flexibility == FLEXIBLE_LOWER_BOUND) return false
|
||||
|
||||
// even if flexibility is FLEXIBLE_UPPER_BOUND it's still can be not nullable for supetypes and annotation parameters
|
||||
return !isForAnnotationParameter && howThisTypeIsUsed != SUPERTYPE
|
||||
}
|
||||
}
|
||||
|
||||
internal fun makeStarProjection(
|
||||
typeParameter: TypeParameterDescriptor,
|
||||
attr: JavaTypeAttributes
|
||||
): TypeProjection {
|
||||
return if (attr.howThisTypeIsUsed == SUPERTYPE)
|
||||
TypeProjectionImpl(typeParameter.starProjectionType())
|
||||
else
|
||||
StarProjectionImpl(typeParameter)
|
||||
}
|
||||
|
||||
data class JavaTypeAttributes(
|
||||
val howThisTypeIsUsed: TypeUsage,
|
||||
val flexibility: JavaTypeFlexibility = INFLEXIBLE,
|
||||
val isForAnnotationParameter: Boolean = false,
|
||||
// Current type is upper bound of this type parameter
|
||||
val upperBoundOfTypeParameter: TypeParameterDescriptor? = null
|
||||
) {
|
||||
fun withFlexibility(flexibility: JavaTypeFlexibility) = copy(flexibility = flexibility)
|
||||
}
|
||||
|
||||
enum class JavaTypeFlexibility {
|
||||
INFLEXIBLE,
|
||||
FLEXIBLE_UPPER_BOUND,
|
||||
FLEXIBLE_LOWER_BOUND
|
||||
}
|
||||
|
||||
fun TypeUsage.toAttributes(
|
||||
isForAnnotationParameter: Boolean = false,
|
||||
upperBoundForTypeParameter: TypeParameterDescriptor? = null
|
||||
) = JavaTypeAttributes(
|
||||
this,
|
||||
isForAnnotationParameter = isForAnnotationParameter,
|
||||
upperBoundOfTypeParameter = upperBoundForTypeParameter
|
||||
)
|
||||
|
||||
// Definition:
|
||||
// ErasedUpperBound(T : G<t>) = G<*> // UpperBound(T) is a type G<t> with arguments
|
||||
// ErasedUpperBound(T : A) = A // UpperBound(T) is a type A without arguments
|
||||
// ErasedUpperBound(T : F) = UpperBound(F) // UB(T) is another type parameter F
|
||||
internal fun TypeParameterDescriptor.getErasedUpperBound(
|
||||
// Calculation of `potentiallyRecursiveTypeParameter.upperBounds` may recursively depend on `this.getErasedUpperBound`
|
||||
// E.g. `class A<T extends A, F extends A>`
|
||||
// To prevent recursive calls return defaultValue() instead
|
||||
potentiallyRecursiveTypeParameter: TypeParameterDescriptor? = null,
|
||||
defaultValue: (() -> KotlinType) = { ErrorUtils.createErrorType("Can't compute erased upper bound of type parameter `$this`") }
|
||||
): KotlinType {
|
||||
if (this === potentiallyRecursiveTypeParameter) return defaultValue()
|
||||
|
||||
val firstUpperBound = upperBounds.first()
|
||||
|
||||
if (firstUpperBound.constructor.declarationDescriptor is ClassDescriptor) {
|
||||
return firstUpperBound.replaceArgumentsWithStarProjections()
|
||||
}
|
||||
|
||||
val stopAt = potentiallyRecursiveTypeParameter ?: this
|
||||
var current = firstUpperBound.constructor.declarationDescriptor as TypeParameterDescriptor
|
||||
|
||||
while (current != stopAt) {
|
||||
val nextUpperBound = current.upperBounds.first()
|
||||
if (nextUpperBound.constructor.declarationDescriptor is ClassDescriptor) {
|
||||
return nextUpperBound.replaceArgumentsWithStarProjections()
|
||||
}
|
||||
|
||||
current = nextUpperBound.constructor.declarationDescriptor as TypeParameterDescriptor
|
||||
}
|
||||
|
||||
return defaultValue()
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.lazy.types
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRendererOptions
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
|
||||
class RawTypeImpl(lowerBound: SimpleType, upperBound: SimpleType) : FlexibleType(lowerBound, upperBound), RawType {
|
||||
init {
|
||||
assert (KotlinTypeChecker.DEFAULT.isSubtypeOf(lowerBound, upperBound)) {
|
||||
"Lower bound $lowerBound of a flexible type must be a subtype of the upper bound $upperBound"
|
||||
}
|
||||
}
|
||||
|
||||
override val delegate: SimpleType get() = lowerBound
|
||||
|
||||
override val memberScope: MemberScope
|
||||
get() {
|
||||
val classDescriptor = constructor.declarationDescriptor as? ClassDescriptor
|
||||
?: error("Incorrect classifier: ${constructor.declarationDescriptor}")
|
||||
return classDescriptor.getMemberScope(RawSubstitution)
|
||||
}
|
||||
|
||||
override fun replaceAnnotations(newAnnotations: Annotations)
|
||||
= RawTypeImpl(lowerBound.replaceAnnotations(newAnnotations), upperBound.replaceAnnotations(newAnnotations))
|
||||
|
||||
override fun makeNullableAsSpecified(newNullability: Boolean)
|
||||
= RawTypeImpl(lowerBound.makeNullableAsSpecified(newNullability), upperBound.makeNullableAsSpecified(newNullability))
|
||||
|
||||
override fun render(renderer: DescriptorRenderer, options: DescriptorRendererOptions): String {
|
||||
fun onlyOutDiffers(first: String, second: String) = first == second.removePrefix("out ") || second == "*"
|
||||
|
||||
fun renderArguments(type: KotlinType) = type.arguments.map { renderer.renderTypeProjection(it) }
|
||||
|
||||
fun String.replaceArgs(newArgs: String): String {
|
||||
if (!contains('<')) return this
|
||||
return "${substringBefore('<')}<$newArgs>${substringAfterLast('>')}"
|
||||
}
|
||||
|
||||
val lowerRendered = renderer.renderType(lowerBound)
|
||||
val upperRendered = renderer.renderType(upperBound)
|
||||
|
||||
if (options.debugMode) {
|
||||
return "raw ($lowerRendered..$upperRendered)"
|
||||
}
|
||||
if (upperBound.arguments.isEmpty()) return renderer.renderFlexibleType(lowerRendered, upperRendered, builtIns)
|
||||
|
||||
val lowerArgs = renderArguments(lowerBound)
|
||||
val upperArgs = renderArguments(upperBound)
|
||||
val newArgs = lowerArgs.joinToString(", ") { "(raw) $it" }
|
||||
val newUpper =
|
||||
if (lowerArgs.zip(upperArgs).all { onlyOutDiffers(it.first, it.second) })
|
||||
upperRendered.replaceArgs(newArgs)
|
||||
else upperRendered
|
||||
val newLower = lowerRendered.replaceArgs(newArgs)
|
||||
if (newLower == newUpper) return newLower
|
||||
return renderer.renderFlexibleType(newLower, newUpper, builtIns)
|
||||
}
|
||||
}
|
||||
|
||||
internal object RawSubstitution : TypeSubstitution() {
|
||||
override fun get(key: KotlinType) = TypeProjectionImpl(eraseType(key))
|
||||
|
||||
private val lowerTypeAttr = TypeUsage.COMMON.toAttributes().withFlexibility(JavaTypeFlexibility.FLEXIBLE_LOWER_BOUND)
|
||||
private val upperTypeAttr = TypeUsage.COMMON.toAttributes().withFlexibility(JavaTypeFlexibility.FLEXIBLE_UPPER_BOUND)
|
||||
|
||||
private fun eraseType(type: KotlinType): KotlinType {
|
||||
val declaration = type.constructor.declarationDescriptor
|
||||
return when (declaration) {
|
||||
is TypeParameterDescriptor -> eraseType(declaration.getErasedUpperBound())
|
||||
is ClassDescriptor -> {
|
||||
val (lower, isRawL) = eraseInflexibleBasedOnClassDescriptor(type.lowerIfFlexible(), declaration, lowerTypeAttr)
|
||||
val (upper, isRawU) = eraseInflexibleBasedOnClassDescriptor(type.upperIfFlexible(), declaration, upperTypeAttr)
|
||||
|
||||
if (isRawL || isRawU) {
|
||||
RawTypeImpl(lower, upper)
|
||||
}
|
||||
else {
|
||||
KotlinTypeFactory.flexibleType(lower, upper)
|
||||
}
|
||||
}
|
||||
else -> error("Unexpected declaration kind: $declaration")
|
||||
}
|
||||
}
|
||||
|
||||
// false means that type cannot be raw
|
||||
private fun eraseInflexibleBasedOnClassDescriptor(
|
||||
type: SimpleType, declaration: ClassDescriptor, attr: JavaTypeAttributes
|
||||
): Pair<SimpleType, Boolean> {
|
||||
if (type.constructor.parameters.isEmpty()) return type to false
|
||||
|
||||
if (KotlinBuiltIns.isArray(type)) {
|
||||
val componentTypeProjection = type.arguments[0]
|
||||
val arguments = listOf(
|
||||
TypeProjectionImpl(componentTypeProjection.projectionKind, eraseType(componentTypeProjection.type))
|
||||
)
|
||||
return KotlinTypeFactory.simpleType(
|
||||
type.annotations, type.constructor, arguments, type.isMarkedNullable
|
||||
) to false
|
||||
}
|
||||
|
||||
if (type.isError) return ErrorUtils.createErrorType("Raw error type: ${type.constructor}") to false
|
||||
|
||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
|
||||
type.annotations, type.constructor,
|
||||
type.constructor.parameters.map {
|
||||
parameter ->
|
||||
computeProjection(parameter, attr)
|
||||
},
|
||||
type.isMarkedNullable, declaration.getMemberScope(RawSubstitution)
|
||||
) to true
|
||||
}
|
||||
|
||||
fun computeProjection(
|
||||
parameter: TypeParameterDescriptor,
|
||||
attr: JavaTypeAttributes,
|
||||
erasedUpperBound: KotlinType = parameter.getErasedUpperBound()
|
||||
) = when (attr.flexibility) {
|
||||
// Raw(List<T>) => (List<Any?>..List<*>)
|
||||
// Raw(Enum<T>) => (Enum<Enum<*>>..Enum<out Enum<*>>)
|
||||
// In the last case upper bound is equal to star projection `Enum<*>`,
|
||||
// but we want to keep matching tree structure of flexible bounds (at least they should have the same size)
|
||||
JavaTypeFlexibility.FLEXIBLE_LOWER_BOUND -> TypeProjectionImpl(
|
||||
// T : String -> String
|
||||
// in T : String -> String
|
||||
// T : Enum<T> -> Enum<*>
|
||||
Variance.INVARIANT, erasedUpperBound
|
||||
)
|
||||
JavaTypeFlexibility.FLEXIBLE_UPPER_BOUND, JavaTypeFlexibility.INFLEXIBLE -> {
|
||||
if (!parameter.variance.allowsOutPosition)
|
||||
// in T -> Comparable<Nothing>
|
||||
TypeProjectionImpl(Variance.INVARIANT, parameter.builtIns.nothingType)
|
||||
else if (erasedUpperBound.constructor.parameters.isNotEmpty())
|
||||
// T : Enum<E> -> out Enum<*>
|
||||
TypeProjectionImpl(Variance.OUT_VARIANCE, erasedUpperBound)
|
||||
else
|
||||
// T : String -> *
|
||||
makeStarProjection(parameter, attr)
|
||||
}
|
||||
}
|
||||
|
||||
override fun isEmpty() = false
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.name.Name
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
|
||||
import org.jetbrains.kotlin.load.java.BuiltinSpecialProperties.getPropertyNameCandidatesBySpecialGetterName
|
||||
|
||||
|
||||
fun propertyNameByGetMethodName(methodName: Name): Name?
|
||||
= propertyNameFromAccessorMethodName(methodName, "get") ?: propertyNameFromAccessorMethodName(methodName, "is", removePrefix = false)
|
||||
|
||||
fun propertyNameBySetMethodName(methodName: Name, withIsPrefix: Boolean): Name?
|
||||
= propertyNameFromAccessorMethodName(methodName, "set", addPrefix = if (withIsPrefix) "is" else null)
|
||||
|
||||
fun propertyNamesBySetMethodName(methodName: Name)
|
||||
= listOf(propertyNameBySetMethodName(methodName, false), propertyNameBySetMethodName(methodName, true)).filterNotNull()
|
||||
|
||||
private fun propertyNameFromAccessorMethodName(methodName: Name, prefix: String, removePrefix: Boolean = true, addPrefix: String? = null): Name? {
|
||||
if (methodName.isSpecial) return null
|
||||
val identifier = methodName.identifier
|
||||
if (!identifier.startsWith(prefix)) return null
|
||||
if (identifier.length == prefix.length) return null
|
||||
if (identifier[prefix.length] in 'a'..'z') return null
|
||||
|
||||
if (addPrefix != null) {
|
||||
assert(removePrefix)
|
||||
return Name.identifier(addPrefix + identifier.removePrefix(prefix))
|
||||
}
|
||||
|
||||
if (!removePrefix) return methodName
|
||||
val name = identifier.removePrefix(prefix).decapitalizeSmart(asciiOnly = true)
|
||||
if (!Name.isValidIdentifier(name)) return null
|
||||
return Name.identifier(name)
|
||||
}
|
||||
|
||||
fun getPropertyNamesCandidatesByAccessorName(name: Name): List<Name> {
|
||||
val nameAsString = name.asString()
|
||||
|
||||
if (JvmAbi.isGetterName(nameAsString)) {
|
||||
return listOfNotNull(propertyNameByGetMethodName(name))
|
||||
}
|
||||
|
||||
if (JvmAbi.isSetterName(nameAsString)) {
|
||||
return propertyNamesBySetMethodName(name)
|
||||
}
|
||||
|
||||
return getPropertyNameCandidatesBySpecialGetterName(name)
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.sources
|
||||
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaElement
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
|
||||
interface JavaSourceElementFactory {
|
||||
fun source(javaElement: JavaElement): JavaSourceElement
|
||||
}
|
||||
|
||||
interface JavaSourceElement: SourceElement {
|
||||
val javaElement: JavaElement
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:JvmName("SpecialBuiltinMembers")
|
||||
package org.jetbrains.kotlin.load.java
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.getSpecialSignatureInfo
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.sameAsBuiltinMethodWithErasedValueParameters
|
||||
import org.jetbrains.kotlin.load.java.BuiltinSpecialProperties.getBuiltinSpecialPropertyGetterName
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||
import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
|
||||
import org.jetbrains.kotlin.load.kotlin.computeJvmSignature
|
||||
import org.jetbrains.kotlin.load.kotlin.signatures
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.firstOverridden
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES as BUILTIN_NAMES
|
||||
|
||||
private fun FqName.child(name: String): FqName = child(Name.identifier(name))
|
||||
private fun FqNameUnsafe.childSafe(name: String): FqName = child(Name.identifier(name)).toSafe()
|
||||
|
||||
private data class NameAndSignature(val name: Name, val signature: String)
|
||||
|
||||
private fun String.method(name: String, parameters: String, returnType: String) =
|
||||
NameAndSignature(
|
||||
Name.identifier(name),
|
||||
SignatureBuildingComponents.signature(this@method, "$name($parameters)$returnType"))
|
||||
|
||||
object BuiltinSpecialProperties {
|
||||
val PROPERTY_FQ_NAME_TO_JVM_GETTER_NAME_MAP = mapOf(
|
||||
BUILTIN_NAMES._enum.childSafe("name") to Name.identifier("name"),
|
||||
BUILTIN_NAMES._enum.childSafe("ordinal") to Name.identifier("ordinal"),
|
||||
BUILTIN_NAMES.collection.child("size") to Name.identifier("size"),
|
||||
BUILTIN_NAMES.map.child("size") to Name.identifier("size"),
|
||||
BUILTIN_NAMES.charSequence.childSafe("length") to Name.identifier("length"),
|
||||
BUILTIN_NAMES.map.child("keys") to Name.identifier("keySet"),
|
||||
BUILTIN_NAMES.map.child("values") to Name.identifier("values"),
|
||||
BUILTIN_NAMES.map.child("entries") to Name.identifier("entrySet")
|
||||
)
|
||||
|
||||
private val GETTER_JVM_NAME_TO_PROPERTIES_SHORT_NAME_MAP: Map<Name, List<Name>> =
|
||||
PROPERTY_FQ_NAME_TO_JVM_GETTER_NAME_MAP.entries
|
||||
.map { Pair(it.key.shortName(), it.value) }
|
||||
.groupBy({ it.second }, { it.first })
|
||||
|
||||
private val SPECIAL_FQ_NAMES = PROPERTY_FQ_NAME_TO_JVM_GETTER_NAME_MAP.keys
|
||||
internal val SPECIAL_SHORT_NAMES = SPECIAL_FQ_NAMES.map(FqName::shortName).toSet()
|
||||
|
||||
fun hasBuiltinSpecialPropertyFqName(callableMemberDescriptor: CallableMemberDescriptor): Boolean {
|
||||
if (callableMemberDescriptor.name !in SPECIAL_SHORT_NAMES) return false
|
||||
|
||||
return callableMemberDescriptor.hasBuiltinSpecialPropertyFqNameImpl()
|
||||
}
|
||||
|
||||
private fun CallableMemberDescriptor.hasBuiltinSpecialPropertyFqNameImpl(): Boolean {
|
||||
if (fqNameOrNull() in SPECIAL_FQ_NAMES && valueParameters.isEmpty()) return true
|
||||
if (!KotlinBuiltIns.isBuiltIn(this)) return false
|
||||
|
||||
return overriddenDescriptors.any { hasBuiltinSpecialPropertyFqName(it) }
|
||||
}
|
||||
|
||||
fun getPropertyNameCandidatesBySpecialGetterName(name1: Name): List<Name> =
|
||||
GETTER_JVM_NAME_TO_PROPERTIES_SHORT_NAME_MAP[name1] ?: emptyList()
|
||||
|
||||
fun CallableMemberDescriptor.getBuiltinSpecialPropertyGetterName(): String? {
|
||||
assert(KotlinBuiltIns.isBuiltIn(this)) { "This method is defined only for builtin members, but $this found" }
|
||||
|
||||
val descriptor = propertyIfAccessor.firstOverridden { hasBuiltinSpecialPropertyFqName(it) } ?: return null
|
||||
return PROPERTY_FQ_NAME_TO_JVM_GETTER_NAME_MAP[descriptor.fqNameSafe]?.asString()
|
||||
}
|
||||
}
|
||||
|
||||
object BuiltinMethodsWithSpecialGenericSignature {
|
||||
private val ERASED_COLLECTION_PARAMETER_NAME_AND_SIGNATURES = setOf(
|
||||
"containsAll", "removeAll", "retainAll"
|
||||
).map { "java/util/Collection".method(it, "Ljava/util/Collection;", JvmPrimitiveType.BOOLEAN.desc) }
|
||||
|
||||
private val ERASED_COLLECTION_PARAMETER_SIGNATURES = ERASED_COLLECTION_PARAMETER_NAME_AND_SIGNATURES.map { it.signature }
|
||||
val ERASED_COLLECTION_PARAMETER_NAMES = ERASED_COLLECTION_PARAMETER_NAME_AND_SIGNATURES.map { it.name.asString() }
|
||||
|
||||
enum class TypeSafeBarrierDescription(val defaultValue: Any?) {
|
||||
NULL(null), INDEX(-1), FALSE(false),
|
||||
|
||||
MAP_GET_OR_DEFAULT(null) {
|
||||
override fun checkParameter(index: Int) = index != 1
|
||||
};
|
||||
|
||||
open fun checkParameter(index: Int) = true
|
||||
}
|
||||
|
||||
private val GENERIC_PARAMETERS_METHODS_TO_DEFAULT_VALUES_MAP =
|
||||
signatures {
|
||||
mapOf(
|
||||
javaUtil("Collection")
|
||||
.method("contains", "Ljava/lang/Object;", JvmPrimitiveType.BOOLEAN.desc) to TypeSafeBarrierDescription.FALSE,
|
||||
javaUtil("Collection")
|
||||
.method("remove", "Ljava/lang/Object;", JvmPrimitiveType.BOOLEAN.desc) to TypeSafeBarrierDescription.FALSE,
|
||||
|
||||
javaUtil("Map")
|
||||
.method("containsKey", "Ljava/lang/Object;", JvmPrimitiveType.BOOLEAN.desc) to TypeSafeBarrierDescription.FALSE,
|
||||
javaUtil("Map")
|
||||
.method("containsValue", "Ljava/lang/Object;", JvmPrimitiveType.BOOLEAN.desc) to TypeSafeBarrierDescription.FALSE,
|
||||
javaUtil("Map")
|
||||
.method("remove", "Ljava/lang/Object;Ljava/lang/Object;",
|
||||
JvmPrimitiveType.BOOLEAN.desc) to TypeSafeBarrierDescription.FALSE,
|
||||
|
||||
javaUtil("Map")
|
||||
.method("getOrDefault", "Ljava/lang/Object;Ljava/lang/Object;",
|
||||
"Ljava/lang/Object;") to TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT,
|
||||
|
||||
javaUtil("Map")
|
||||
.method("get", "Ljava/lang/Object;", "Ljava/lang/Object;") to TypeSafeBarrierDescription.NULL,
|
||||
javaUtil("Map")
|
||||
.method("remove", "Ljava/lang/Object;", "Ljava/lang/Object;") to TypeSafeBarrierDescription.NULL,
|
||||
|
||||
javaUtil("List")
|
||||
.method("indexOf", "Ljava/lang/Object;", JvmPrimitiveType.INT.desc) to TypeSafeBarrierDescription.INDEX,
|
||||
javaUtil("List")
|
||||
.method("lastIndexOf", "Ljava/lang/Object;", JvmPrimitiveType.INT.desc) to TypeSafeBarrierDescription.INDEX
|
||||
)
|
||||
}
|
||||
|
||||
private val SIGNATURE_TO_DEFAULT_VALUES_MAP = GENERIC_PARAMETERS_METHODS_TO_DEFAULT_VALUES_MAP.mapKeys { it.key.signature }
|
||||
private val ERASED_VALUE_PARAMETERS_SHORT_NAMES: Set<Name>
|
||||
val ERASED_VALUE_PARAMETERS_SIGNATURES: Set<String>
|
||||
|
||||
init {
|
||||
val allMethods = GENERIC_PARAMETERS_METHODS_TO_DEFAULT_VALUES_MAP.keys + ERASED_COLLECTION_PARAMETER_NAME_AND_SIGNATURES
|
||||
ERASED_VALUE_PARAMETERS_SHORT_NAMES = allMethods.map { it.name }.toSet()
|
||||
ERASED_VALUE_PARAMETERS_SIGNATURES = allMethods.map { it.signature }.toSet()
|
||||
}
|
||||
|
||||
private val CallableMemberDescriptor.hasErasedValueParametersInJava: Boolean
|
||||
get() = computeJvmSignature() in ERASED_VALUE_PARAMETERS_SIGNATURES
|
||||
|
||||
@JvmStatic
|
||||
fun getOverriddenBuiltinFunctionWithErasedValueParametersInJava(
|
||||
functionDescriptor: FunctionDescriptor
|
||||
): FunctionDescriptor? {
|
||||
if (!functionDescriptor.name.sameAsBuiltinMethodWithErasedValueParameters) return null
|
||||
return functionDescriptor.firstOverridden { it.hasErasedValueParametersInJava } as FunctionDescriptor?
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDefaultValueForOverriddenBuiltinFunction(functionDescriptor: FunctionDescriptor): TypeSafeBarrierDescription? {
|
||||
if (functionDescriptor.name !in ERASED_VALUE_PARAMETERS_SHORT_NAMES) return null
|
||||
return functionDescriptor.firstOverridden {
|
||||
it.computeJvmSignature() in SIGNATURE_TO_DEFAULT_VALUES_MAP.keys
|
||||
}?.let { SIGNATURE_TO_DEFAULT_VALUES_MAP[it.computeJvmSignature()] }
|
||||
}
|
||||
|
||||
val Name.sameAsBuiltinMethodWithErasedValueParameters: Boolean
|
||||
get () = this in ERASED_VALUE_PARAMETERS_SHORT_NAMES
|
||||
|
||||
enum class SpecialSignatureInfo(val valueParametersSignature: String?, val isObjectReplacedWithTypeParameter: Boolean) {
|
||||
ONE_COLLECTION_PARAMETER("Ljava/util/Collection<+Ljava/lang/Object;>;", false),
|
||||
OBJECT_PARAMETER_NON_GENERIC(null, true),
|
||||
OBJECT_PARAMETER_GENERIC("Ljava/lang/Object;", true)
|
||||
}
|
||||
|
||||
fun CallableMemberDescriptor.isBuiltinWithSpecialDescriptorInJvm(): Boolean {
|
||||
if (!KotlinBuiltIns.isBuiltIn(this)) return false
|
||||
return getSpecialSignatureInfo()?.isObjectReplacedWithTypeParameter ?: false || doesOverrideBuiltinWithDifferentJvmName()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun CallableMemberDescriptor.getSpecialSignatureInfo(): SpecialSignatureInfo? {
|
||||
if (name !in ERASED_VALUE_PARAMETERS_SHORT_NAMES) return null
|
||||
|
||||
val builtinSignature = firstOverridden { it is FunctionDescriptor && it.hasErasedValueParametersInJava }?.computeJvmSignature()
|
||||
?: return null
|
||||
|
||||
if (builtinSignature in ERASED_COLLECTION_PARAMETER_SIGNATURES) return SpecialSignatureInfo.ONE_COLLECTION_PARAMETER
|
||||
|
||||
val defaultValue = SIGNATURE_TO_DEFAULT_VALUES_MAP[builtinSignature]!!
|
||||
|
||||
return if (defaultValue == TypeSafeBarrierDescription.NULL)
|
||||
// return type is some generic type as 'Map.get'
|
||||
SpecialSignatureInfo.OBJECT_PARAMETER_GENERIC
|
||||
else
|
||||
SpecialSignatureInfo.OBJECT_PARAMETER_NON_GENERIC
|
||||
}
|
||||
}
|
||||
|
||||
object BuiltinMethodsWithDifferentJvmName {
|
||||
// Note that signatures here are not real,
|
||||
// e.g. 'java/lang/CharSequence.get(I)C' does not actually exist in JDK
|
||||
// But it doesn't matter here, because signatures are only used to distinguish overloaded built-in definitions
|
||||
private val REMOVE_AT_NAME_AND_SIGNATURE =
|
||||
"java/util/List".method("removeAt", JvmPrimitiveType.INT.desc, "Ljava/lang/Object;")
|
||||
|
||||
private val NAME_AND_SIGNATURE_TO_JVM_REPRESENTATION_NAME_MAP: Map<NameAndSignature, Name> = signatures {
|
||||
mapOf(
|
||||
javaLang("Number").method("toByte", "", JvmPrimitiveType.BYTE.desc) to Name.identifier("byteValue"),
|
||||
javaLang("Number").method("toShort", "", JvmPrimitiveType.SHORT.desc) to Name.identifier("shortValue"),
|
||||
javaLang("Number").method("toInt", "", JvmPrimitiveType.INT.desc) to Name.identifier("intValue"),
|
||||
javaLang("Number").method("toLong", "", JvmPrimitiveType.LONG.desc) to Name.identifier("longValue"),
|
||||
javaLang("Number").method("toFloat", "", JvmPrimitiveType.FLOAT.desc) to Name.identifier("floatValue"),
|
||||
javaLang("Number").method("toDouble", "", JvmPrimitiveType.DOUBLE.desc) to Name.identifier("doubleValue"),
|
||||
REMOVE_AT_NAME_AND_SIGNATURE to Name.identifier("remove"),
|
||||
javaLang("CharSequence")
|
||||
.method("get", JvmPrimitiveType.INT.desc, JvmPrimitiveType.CHAR.desc) to Name.identifier("charAt")
|
||||
)
|
||||
}
|
||||
|
||||
private val SIGNATURE_TO_JVM_REPRESENTATION_NAME: Map<String, Name> =
|
||||
NAME_AND_SIGNATURE_TO_JVM_REPRESENTATION_NAME_MAP.mapKeys { it.key.signature }
|
||||
|
||||
val ORIGINAL_SHORT_NAMES: List<Name> = NAME_AND_SIGNATURE_TO_JVM_REPRESENTATION_NAME_MAP.keys.map { it.name }
|
||||
|
||||
private val JVM_SHORT_NAME_TO_BUILTIN_SHORT_NAMES_MAP: Map<Name, List<Name>> =
|
||||
NAME_AND_SIGNATURE_TO_JVM_REPRESENTATION_NAME_MAP.entries
|
||||
.map { Pair(it.key.name, it.value) }
|
||||
.groupBy({ it.second }, { it.first })
|
||||
|
||||
val Name.sameAsRenamedInJvmBuiltin: Boolean
|
||||
get() = this in ORIGINAL_SHORT_NAMES
|
||||
|
||||
fun getJvmName(functionDescriptor: SimpleFunctionDescriptor): Name? {
|
||||
return SIGNATURE_TO_JVM_REPRESENTATION_NAME[functionDescriptor.computeJvmSignature() ?: return null]
|
||||
}
|
||||
|
||||
fun isBuiltinFunctionWithDifferentNameInJvm(functionDescriptor: SimpleFunctionDescriptor): Boolean {
|
||||
return KotlinBuiltIns.isBuiltIn(functionDescriptor) && functionDescriptor.firstOverridden {
|
||||
SIGNATURE_TO_JVM_REPRESENTATION_NAME.containsKey(functionDescriptor.computeJvmSignature())
|
||||
} != null
|
||||
}
|
||||
|
||||
fun getBuiltinFunctionNamesByJvmName(name: Name): List<Name> =
|
||||
JVM_SHORT_NAME_TO_BUILTIN_SHORT_NAMES_MAP[name] ?: emptyList()
|
||||
|
||||
|
||||
val SimpleFunctionDescriptor.isRemoveAtByIndex: Boolean
|
||||
get() = name.asString() == "removeAt" && computeJvmSignature() == REMOVE_AT_NAME_AND_SIGNATURE.signature
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : CallableMemberDescriptor> T.getOverriddenBuiltinWithDifferentJvmName(): T? {
|
||||
if (name !in BuiltinMethodsWithDifferentJvmName.ORIGINAL_SHORT_NAMES
|
||||
&& propertyIfAccessor.name !in BuiltinSpecialProperties.SPECIAL_SHORT_NAMES) return null
|
||||
|
||||
return when (this) {
|
||||
is PropertyDescriptor, is PropertyAccessorDescriptor ->
|
||||
firstOverridden { BuiltinSpecialProperties.hasBuiltinSpecialPropertyFqName(it.propertyIfAccessor) } as T?
|
||||
is SimpleFunctionDescriptor ->
|
||||
firstOverridden {
|
||||
BuiltinMethodsWithDifferentJvmName.isBuiltinFunctionWithDifferentNameInJvm(it as SimpleFunctionDescriptor)
|
||||
} as T?
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun CallableMemberDescriptor.doesOverrideBuiltinWithDifferentJvmName(): Boolean = getOverriddenBuiltinWithDifferentJvmName() != null
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : CallableMemberDescriptor> T.getOverriddenSpecialBuiltin(): T? {
|
||||
getOverriddenBuiltinWithDifferentJvmName()?.let { return it }
|
||||
|
||||
if (!name.sameAsBuiltinMethodWithErasedValueParameters) return null
|
||||
|
||||
return firstOverridden {
|
||||
KotlinBuiltIns.isBuiltIn(it) && it.getSpecialSignatureInfo() != null
|
||||
} as T?
|
||||
}
|
||||
|
||||
// The subtle difference between getOverriddenBuiltinReflectingJvmDescriptor and getOverriddenSpecialBuiltin
|
||||
// is that first one return descriptor reflecting JVM signature (JVM descriptor)
|
||||
// E.g. it returns `contains(e: E): Boolean` instead of `contains(e: String): Boolean` for implementation of Collection<String>.contains
|
||||
// Implementation differs by getting 'original' for collection methods with erased value parameters
|
||||
// Also it ignores Collection<String>.containsAll overrides because they have the same JVM descriptor
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : CallableMemberDescriptor> T.getOverriddenBuiltinReflectingJvmDescriptor(): T? {
|
||||
getOverriddenBuiltinWithDifferentJvmName()?.let { return it }
|
||||
|
||||
if (!name.sameAsBuiltinMethodWithErasedValueParameters) return null
|
||||
|
||||
return firstOverridden {
|
||||
KotlinBuiltIns.isBuiltIn(it) && it.getSpecialSignatureInfo()?.isObjectReplacedWithTypeParameter ?: false
|
||||
}?.original as T?
|
||||
}
|
||||
|
||||
fun getJvmMethodNameIfSpecial(callableMemberDescriptor: CallableMemberDescriptor): String? {
|
||||
val overriddenBuiltin = getOverriddenBuiltinThatAffectsJvmName(callableMemberDescriptor)?.propertyIfAccessor
|
||||
?: return null
|
||||
return when (overriddenBuiltin) {
|
||||
is PropertyDescriptor -> overriddenBuiltin.getBuiltinSpecialPropertyGetterName()
|
||||
is SimpleFunctionDescriptor -> BuiltinMethodsWithDifferentJvmName.getJvmName(overriddenBuiltin)?.asString()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOverriddenBuiltinThatAffectsJvmName(
|
||||
callableMemberDescriptor: CallableMemberDescriptor
|
||||
): CallableMemberDescriptor? =
|
||||
if (KotlinBuiltIns.isBuiltIn(callableMemberDescriptor)) callableMemberDescriptor.getOverriddenBuiltinWithDifferentJvmName()
|
||||
else null
|
||||
|
||||
fun ClassDescriptor.hasRealKotlinSuperClassWithOverrideOf(
|
||||
specialCallableDescriptor: CallableDescriptor
|
||||
): Boolean {
|
||||
val builtinContainerDefaultType = (specialCallableDescriptor.containingDeclaration as ClassDescriptor).defaultType
|
||||
|
||||
var superClassDescriptor = DescriptorUtils.getSuperClassDescriptor(this)
|
||||
|
||||
while (superClassDescriptor != null) {
|
||||
if (superClassDescriptor !is JavaClassDescriptor) {
|
||||
// Kotlin class
|
||||
|
||||
val doesOverrideBuiltinDeclaration =
|
||||
TypeCheckingProcedure.findCorrespondingSupertype(superClassDescriptor.defaultType, builtinContainerDefaultType) != null
|
||||
|
||||
if (doesOverrideBuiltinDeclaration) {
|
||||
return !KotlinBuiltIns.isBuiltIn(superClassDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
superClassDescriptor = DescriptorUtils.getSuperClassDescriptor(superClassDescriptor)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Util methods
|
||||
val CallableMemberDescriptor.isFromJava: Boolean
|
||||
get() = propertyIfAccessor.let { descriptor ->
|
||||
(descriptor as? JavaCallableMemberDescriptor)?.containingDeclaration is JavaClassDescriptor
|
||||
}
|
||||
|
||||
fun CallableMemberDescriptor.isFromJavaOrBuiltins() = isFromJava || KotlinBuiltIns.isBuiltIn(this)
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.structure
|
||||
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
interface JavaAnnotationArgument {
|
||||
val name: Name?
|
||||
}
|
||||
|
||||
interface JavaLiteralAnnotationArgument : JavaAnnotationArgument {
|
||||
val value: Any?
|
||||
}
|
||||
|
||||
interface JavaArrayAnnotationArgument : JavaAnnotationArgument {
|
||||
fun getElements(): List<JavaAnnotationArgument>
|
||||
}
|
||||
|
||||
interface JavaEnumValueAnnotationArgument : JavaAnnotationArgument {
|
||||
val entryName: Name?
|
||||
fun resolve(): JavaField?
|
||||
}
|
||||
|
||||
interface JavaClassObjectAnnotationArgument : JavaAnnotationArgument {
|
||||
fun getReferencedType(): JavaType
|
||||
}
|
||||
|
||||
interface JavaAnnotationAsAnnotationArgument : JavaAnnotationArgument {
|
||||
fun getAnnotation(): JavaAnnotation
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.structure
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
interface JavaElement
|
||||
|
||||
interface JavaNamedElement : JavaElement {
|
||||
val name: Name
|
||||
}
|
||||
|
||||
interface JavaAnnotationOwner : JavaElement {
|
||||
val annotations: Collection<JavaAnnotation>
|
||||
fun findAnnotation(fqName: FqName): JavaAnnotation?
|
||||
|
||||
val isDeprecatedInJavaDoc: Boolean
|
||||
}
|
||||
|
||||
interface JavaModifierListOwner : JavaElement {
|
||||
val isAbstract: Boolean
|
||||
val isStatic: Boolean
|
||||
val isFinal: Boolean
|
||||
val visibility: Visibility
|
||||
}
|
||||
|
||||
interface JavaTypeParameterListOwner : JavaElement {
|
||||
val typeParameters: List<JavaTypeParameter>
|
||||
}
|
||||
|
||||
interface JavaAnnotation : JavaElement {
|
||||
val arguments: Collection<JavaAnnotationArgument>
|
||||
val classId: ClassId?
|
||||
|
||||
fun resolve(): JavaClass?
|
||||
}
|
||||
|
||||
interface MapBasedJavaAnnotationOwner : JavaAnnotationOwner {
|
||||
val annotationsByFqName: Map<FqName?, JavaAnnotation>
|
||||
override fun findAnnotation(fqName: FqName) = annotationsByFqName[fqName]
|
||||
override val isDeprecatedInJavaDoc: Boolean
|
||||
get() = false
|
||||
}
|
||||
|
||||
fun JavaAnnotationOwner.buildLazyValueForMap() = lazy {
|
||||
annotations.associateBy { it.classId?.asSingleFqName() }
|
||||
}
|
||||
|
||||
interface JavaPackage : JavaElement, JavaAnnotationOwner {
|
||||
val fqName: FqName
|
||||
val subPackages: Collection<JavaPackage>
|
||||
|
||||
fun getClasses(nameFilter: (Name) -> Boolean): Collection<JavaClass>
|
||||
}
|
||||
|
||||
interface JavaClassifier : JavaNamedElement, JavaAnnotationOwner
|
||||
|
||||
interface JavaClass : JavaClassifier, JavaTypeParameterListOwner, JavaModifierListOwner {
|
||||
val fqName: FqName?
|
||||
|
||||
val supertypes: Collection<JavaClassifierType>
|
||||
val innerClassNames: Collection<Name>
|
||||
fun findInnerClass(name: Name): JavaClass?
|
||||
val outerClass: JavaClass?
|
||||
|
||||
val isInterface: Boolean
|
||||
val isAnnotationType: Boolean
|
||||
val isEnum: Boolean
|
||||
val lightClassOriginKind: LightClassOriginKind?
|
||||
|
||||
val methods: Collection<JavaMethod>
|
||||
val fields: Collection<JavaField>
|
||||
val constructors: Collection<JavaConstructor>
|
||||
}
|
||||
|
||||
enum class LightClassOriginKind {
|
||||
SOURCE, BINARY
|
||||
}
|
||||
|
||||
interface JavaMember : JavaModifierListOwner, JavaAnnotationOwner, JavaNamedElement {
|
||||
val containingClass: JavaClass
|
||||
}
|
||||
|
||||
interface JavaMethod : JavaMember, JavaTypeParameterListOwner {
|
||||
val valueParameters: List<JavaValueParameter>
|
||||
val returnType: JavaType
|
||||
|
||||
val hasAnnotationParameterDefaultValue: Boolean
|
||||
}
|
||||
|
||||
interface JavaField : JavaMember {
|
||||
val isEnumEntry: Boolean
|
||||
val type: JavaType
|
||||
val initializerValue: Any?
|
||||
val hasConstantNotNullInitializer: Boolean
|
||||
}
|
||||
|
||||
interface JavaConstructor : JavaMember, JavaTypeParameterListOwner {
|
||||
val valueParameters: List<JavaValueParameter>
|
||||
}
|
||||
|
||||
interface JavaValueParameter : JavaAnnotationOwner {
|
||||
val name: Name?
|
||||
val type: JavaType
|
||||
val isVararg: Boolean
|
||||
}
|
||||
|
||||
interface JavaTypeParameter : JavaClassifier {
|
||||
val upperBounds: Collection<JavaClassifierType>
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.structure
|
||||
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
|
||||
interface JavaType
|
||||
|
||||
interface JavaArrayType : JavaType {
|
||||
val componentType: JavaType
|
||||
}
|
||||
|
||||
interface JavaClassifierType : JavaType, JavaAnnotationOwner {
|
||||
val classifier: JavaClassifier?
|
||||
val typeArguments: List<JavaType>
|
||||
|
||||
val isRaw: Boolean
|
||||
|
||||
val classifierQualifiedName: String
|
||||
val presentableText: String
|
||||
}
|
||||
|
||||
interface JavaPrimitiveType : JavaType {
|
||||
/** `null` means the `void` type. */
|
||||
val type: PrimitiveType?
|
||||
}
|
||||
|
||||
interface JavaWildcardType : JavaType {
|
||||
val bound: JavaType?
|
||||
val isExtends: Boolean
|
||||
}
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.typeEnhancement
|
||||
|
||||
import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
|
||||
import org.jetbrains.kotlin.load.kotlin.signatures
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType.BOOLEAN
|
||||
|
||||
class TypeEnhancementInfo(val map: Map<Int, JavaTypeQualifiers>) {
|
||||
constructor(vararg pairs: Pair<Int, JavaTypeQualifiers>) : this(mapOf(*pairs))
|
||||
}
|
||||
|
||||
class PredefinedFunctionEnhancementInfo(
|
||||
val returnTypeInfo: TypeEnhancementInfo? = null,
|
||||
val parametersInfo: List<TypeEnhancementInfo?> = emptyList()
|
||||
)
|
||||
|
||||
/** Type is always nullable: `T?` */
|
||||
private val NULLABLE = JavaTypeQualifiers(NullabilityQualifier.NULLABLE, null, isNotNullTypeParameter = false)
|
||||
/** Nullability depends on substitution, but the type is not platform: `T` */
|
||||
private val NOT_PLATFORM = JavaTypeQualifiers(NullabilityQualifier.NOT_NULL, null, isNotNullTypeParameter = false)
|
||||
/** Type is always non-nullable: `T & Any` */
|
||||
private val NOT_NULLABLE = JavaTypeQualifiers(NullabilityQualifier.NOT_NULL, null, isNotNullTypeParameter = true)
|
||||
|
||||
val PREDEFINED_FUNCTION_ENHANCEMENT_INFO_BY_SIGNATURE = signatures {
|
||||
val JLObject = javaLang("Object")
|
||||
val JFPredicate = javaFunction("Predicate")
|
||||
val JFFunction = javaFunction("Function")
|
||||
val JFConsumer = javaFunction("Consumer")
|
||||
val JFBiFunction = javaFunction("BiFunction")
|
||||
val JFBiConsumer = javaFunction("BiConsumer")
|
||||
val JFUnaryOperator = javaFunction("UnaryOperator")
|
||||
val JUStream = javaUtil("stream/Stream")
|
||||
val JUOptional = javaUtil("Optional")
|
||||
|
||||
enhancement {
|
||||
forClass(javaUtil("Iterator")) {
|
||||
function("forEachRemaining") {
|
||||
parameter(JFConsumer, NOT_PLATFORM, NOT_PLATFORM)
|
||||
}
|
||||
}
|
||||
forClass(javaLang("Iterable")) {
|
||||
function("spliterator") {
|
||||
returns(javaUtil("Spliterator"), NOT_PLATFORM, NOT_PLATFORM)
|
||||
}
|
||||
}
|
||||
forClass(javaUtil("Collection")) {
|
||||
function("removeIf") {
|
||||
parameter(JFPredicate, NOT_PLATFORM, NOT_PLATFORM)
|
||||
returns(BOOLEAN)
|
||||
}
|
||||
function("stream") {
|
||||
returns(JUStream, NOT_PLATFORM, NOT_PLATFORM)
|
||||
}
|
||||
function("parallelStream") {
|
||||
returns(JUStream, NOT_PLATFORM, NOT_PLATFORM)
|
||||
}
|
||||
}
|
||||
forClass(javaUtil("List")) {
|
||||
function("replaceAll") {
|
||||
parameter(JFUnaryOperator, NOT_PLATFORM, NOT_PLATFORM)
|
||||
}
|
||||
}
|
||||
forClass(javaUtil("Map")) {
|
||||
function("forEach") {
|
||||
parameter(JFBiConsumer, NOT_PLATFORM, NOT_PLATFORM, NOT_PLATFORM)
|
||||
}
|
||||
function("putIfAbsent") {
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
returns(JLObject, NULLABLE)
|
||||
}
|
||||
function("replace") {
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
returns(JLObject, NULLABLE)
|
||||
|
||||
}
|
||||
function("replace") {
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
returns(BOOLEAN)
|
||||
}
|
||||
function("replaceAll") {
|
||||
parameter(JFBiFunction, NOT_PLATFORM, NOT_PLATFORM, NOT_PLATFORM, NOT_PLATFORM)
|
||||
}
|
||||
function("compute") {
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
parameter(JFBiFunction, NOT_PLATFORM, NOT_PLATFORM, NULLABLE, NULLABLE)
|
||||
returns(JLObject, NULLABLE)
|
||||
}
|
||||
// while it is possible to return nullable value from lambda in computeIfAbsent,
|
||||
// we deliberately make it just NOT_PLATFORM V in order to have the return type V and not V?
|
||||
function("computeIfAbsent") {
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
parameter(JFFunction, NOT_PLATFORM, NOT_PLATFORM, NOT_PLATFORM)
|
||||
returns(JLObject, NOT_PLATFORM)
|
||||
}
|
||||
function("computeIfPresent") {
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
parameter(JFBiFunction, NOT_PLATFORM, NOT_PLATFORM, NOT_NULLABLE, NULLABLE)
|
||||
returns(JLObject, NULLABLE)
|
||||
}
|
||||
function("merge") {
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
parameter(JLObject, NOT_NULLABLE)
|
||||
parameter(JFBiFunction, NOT_PLATFORM, NOT_NULLABLE, NOT_NULLABLE, NULLABLE)
|
||||
returns(JLObject, NULLABLE)
|
||||
}
|
||||
}
|
||||
forClass(JUOptional) {
|
||||
function("empty") {
|
||||
returns(JUOptional, NOT_PLATFORM, NOT_NULLABLE)
|
||||
}
|
||||
function("of") {
|
||||
parameter(JLObject, NOT_NULLABLE)
|
||||
returns(JUOptional, NOT_PLATFORM, NOT_NULLABLE)
|
||||
}
|
||||
function("ofNullable") {
|
||||
parameter(JLObject, NULLABLE)
|
||||
returns(JUOptional, NOT_PLATFORM, NOT_NULLABLE)
|
||||
}
|
||||
function("get") {
|
||||
returns(JLObject, NOT_NULLABLE)
|
||||
}
|
||||
function("ifPresent") {
|
||||
parameter(JFConsumer, NOT_PLATFORM, NOT_NULLABLE)
|
||||
}
|
||||
}
|
||||
|
||||
forClass(javaLang("ref/Reference")) {
|
||||
function("get") {
|
||||
returns(JLObject, NULLABLE)
|
||||
}
|
||||
}
|
||||
|
||||
forClass(JFPredicate) {
|
||||
function("test") {
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
returns(BOOLEAN)
|
||||
}
|
||||
}
|
||||
forClass(javaFunction("BiPredicate")) {
|
||||
function("test") {
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
returns(BOOLEAN)
|
||||
}
|
||||
}
|
||||
forClass(JFConsumer) {
|
||||
function("accept") {
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
}
|
||||
}
|
||||
forClass(JFBiConsumer) {
|
||||
function("accept") {
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
}
|
||||
}
|
||||
forClass(JFFunction) {
|
||||
function("apply") {
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
returns(JLObject, NOT_PLATFORM)
|
||||
}
|
||||
}
|
||||
forClass(JFBiFunction) {
|
||||
function("apply") {
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
parameter(JLObject, NOT_PLATFORM)
|
||||
returns(JLObject, NOT_PLATFORM)
|
||||
}
|
||||
}
|
||||
forClass(javaFunction("Supplier")) {
|
||||
function("get") {
|
||||
returns(JLObject, NOT_PLATFORM)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private inline fun enhancement(block: SignatureEnhancementBuilder.() -> Unit): Map<String, PredefinedFunctionEnhancementInfo>
|
||||
= SignatureEnhancementBuilder().apply(block).build()
|
||||
|
||||
private class SignatureEnhancementBuilder {
|
||||
private val signatures = mutableMapOf<String, PredefinedFunctionEnhancementInfo>()
|
||||
|
||||
inline fun forClass(internalName: String, block: ClassEnhancementBuilder.() -> Unit) =
|
||||
ClassEnhancementBuilder(internalName).block()
|
||||
|
||||
inner class ClassEnhancementBuilder(val className: String) {
|
||||
fun function(name: String, block: FunctionEnhancementBuilder.() -> Unit) {
|
||||
signatures += FunctionEnhancementBuilder(name).apply(block).build()
|
||||
}
|
||||
|
||||
inner class FunctionEnhancementBuilder(val functionName: String) {
|
||||
private val parameters = mutableListOf<Pair<String, TypeEnhancementInfo?>>()
|
||||
private var returnType: Pair<String, TypeEnhancementInfo?> = "V" to null
|
||||
|
||||
fun parameter(type: String, vararg pairs: Pair<Int, JavaTypeQualifiers>) {
|
||||
parameters += type to
|
||||
if (pairs.isEmpty()) null else TypeEnhancementInfo(*pairs)
|
||||
}
|
||||
fun parameter(type: String, vararg qualifiers: JavaTypeQualifiers) {
|
||||
parameters += type to
|
||||
if (qualifiers.isEmpty()) null else TypeEnhancementInfo(qualifiers.withIndex().associateBy({it.index}, {it.value}))
|
||||
}
|
||||
fun returns(type: String, vararg pairs: Pair<Int, JavaTypeQualifiers>) {
|
||||
returnType = type to TypeEnhancementInfo(*pairs)
|
||||
}
|
||||
fun returns(type: String, vararg qualifiers: JavaTypeQualifiers) {
|
||||
returnType = type to TypeEnhancementInfo(qualifiers.withIndex().associateBy({it.index}, {it.value}))
|
||||
}
|
||||
fun returns(type: JvmPrimitiveType) {
|
||||
returnType = type.desc to null
|
||||
}
|
||||
fun build() = with (SignatureBuildingComponents) {
|
||||
signature(className, jvmDescriptor(functionName, parameters.map { it.first }, returnType.first)) to
|
||||
PredefinedFunctionEnhancementInfo(returnType.second, parameters.map { it.second })
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun build(): Map<String, PredefinedFunctionEnhancementInfo> = signatures
|
||||
}
|
||||
|
||||
|
||||
+449
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.typeEnhancement
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.annotations.composeAnnotations
|
||||
import org.jetbrains.kotlin.load.java.*
|
||||
import org.jetbrains.kotlin.load.java.descriptors.*
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.lazy.copyWithNewDefaultTypeQualifiers
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.isJavaField
|
||||
import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
|
||||
import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgumentValue
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.asFlexibleType
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.isFlexible
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import org.jetbrains.kotlin.types.unwrapEnhancement
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
data class NullabilityQualifierWithMigrationStatus(
|
||||
val qualifier: NullabilityQualifier,
|
||||
val isForWarningOnly: Boolean = false
|
||||
)
|
||||
|
||||
class SignatureEnhancement(private val annotationTypeQualifierResolver: AnnotationTypeQualifierResolver) {
|
||||
|
||||
private fun AnnotationDescriptor.extractNullabilityTypeFromArgument(): NullabilityQualifierWithMigrationStatus? {
|
||||
val enumEntryDescriptor = firstArgumentValue()
|
||||
// if no argument is specified, use default value: NOT_NULL
|
||||
?: return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||
|
||||
if (enumEntryDescriptor !is ClassDescriptor) return null
|
||||
|
||||
return when (enumEntryDescriptor.name.asString()) {
|
||||
"ALWAYS" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||
"MAYBE", "NEVER" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
|
||||
"UNKNOWN" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.FORCE_FLEXIBILITY)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun extractNullability(annotationDescriptor: AnnotationDescriptor): NullabilityQualifierWithMigrationStatus? {
|
||||
extractNullabilityFromKnownAnnotations(annotationDescriptor)?.let { return it }
|
||||
|
||||
val typeQualifierAnnotation =
|
||||
annotationTypeQualifierResolver.resolveTypeQualifierAnnotation(annotationDescriptor)
|
||||
?: return null
|
||||
|
||||
val jsr305State = annotationTypeQualifierResolver.resolveJsr305AnnotationState(annotationDescriptor)
|
||||
if (jsr305State.isIgnore) return null
|
||||
|
||||
return extractNullabilityFromKnownAnnotations(typeQualifierAnnotation)?.copy(isForWarningOnly = jsr305State.isWarning)
|
||||
}
|
||||
|
||||
private fun extractNullabilityFromKnownAnnotations(
|
||||
annotationDescriptor: AnnotationDescriptor
|
||||
): NullabilityQualifierWithMigrationStatus? {
|
||||
val annotationFqName = annotationDescriptor.fqName ?: return null
|
||||
|
||||
return when (annotationFqName) {
|
||||
in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
|
||||
in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
|
||||
JAVAX_NONNULL_ANNOTATION -> annotationDescriptor.extractNullabilityTypeFromArgument()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun <D : CallableMemberDescriptor> enhanceSignatures(c: LazyJavaResolverContext, platformSignatures: Collection<D>): Collection<D> {
|
||||
return platformSignatures.map {
|
||||
it.enhanceSignature(c)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <D : CallableMemberDescriptor> D.enhanceSignature(c: LazyJavaResolverContext): D {
|
||||
// TODO type parameters
|
||||
// TODO use new type parameters while enhancing other types
|
||||
// TODO Propagation into generic type arguments
|
||||
|
||||
if (this !is JavaCallableMemberDescriptor) return this
|
||||
|
||||
// Fake overrides with one overridden has been enhanced before
|
||||
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE && original.overriddenDescriptors.size == 1) return this
|
||||
|
||||
val memberContext = c.copyWithNewDefaultTypeQualifiers(annotations)
|
||||
|
||||
// When loading method as an override for a property, all annotations are stick to its getter
|
||||
val annotationOwnerForMember =
|
||||
if (this is JavaPropertyDescriptor && getter?.isDefault == false)
|
||||
getter!!
|
||||
else
|
||||
this
|
||||
|
||||
val receiverTypeEnhancement =
|
||||
if (extensionReceiverParameter != null)
|
||||
partsForValueParameter(
|
||||
parameterDescriptor =
|
||||
annotationOwnerForMember.safeAs<FunctionDescriptor>()
|
||||
?.getUserData(JavaMethodDescriptor.ORIGINAL_VALUE_PARAMETER_FOR_EXTENSION_RECEIVER),
|
||||
methodContext = memberContext
|
||||
) { it.extensionReceiverParameter!!.type }.enhance()
|
||||
else null
|
||||
|
||||
|
||||
val predefinedEnhancementInfo =
|
||||
(this as? JavaMethodDescriptor)
|
||||
?.run { SignatureBuildingComponents.signature(this.containingDeclaration as ClassDescriptor, this.computeJvmDescriptor()) }
|
||||
?.let { signature -> PREDEFINED_FUNCTION_ENHANCEMENT_INFO_BY_SIGNATURE[signature] }
|
||||
|
||||
|
||||
predefinedEnhancementInfo?.let {
|
||||
assert(it.parametersInfo.size == valueParameters.size) {
|
||||
"Predefined enhancement info for $this has ${it.parametersInfo.size}, but ${valueParameters.size} expected"
|
||||
}
|
||||
}
|
||||
|
||||
val valueParameterEnhancements = annotationOwnerForMember.valueParameters.map {
|
||||
p ->
|
||||
val enhancementResult =partsForValueParameter(p, memberContext) { it.valueParameters[p.index].type }
|
||||
.enhance(predefinedEnhancementInfo?.parametersInfo?.getOrNull(p.index))
|
||||
|
||||
val actualType = if (enhancementResult.wereChanges) enhancementResult.type else p.type
|
||||
val hasDefaultValue = p.hasDefaultValueInAnnotation(actualType)
|
||||
val wereChanges = enhancementResult.wereChanges || (hasDefaultValue != p.declaresDefaultValue())
|
||||
|
||||
ValueParameterEnhancementResult(enhancementResult.type, hasDefaultValue, wereChanges)
|
||||
}
|
||||
|
||||
val returnTypeEnhancement =
|
||||
parts(
|
||||
typeContainer = annotationOwnerForMember, isCovariant = true,
|
||||
containerContext = memberContext,
|
||||
containerApplicabilityType =
|
||||
if (this.safeAs<PropertyDescriptor>()?.isJavaField == true)
|
||||
AnnotationTypeQualifierResolver.QualifierApplicabilityType.FIELD
|
||||
else
|
||||
AnnotationTypeQualifierResolver.QualifierApplicabilityType.METHOD_RETURN_TYPE
|
||||
) { it.returnType!! }.enhance(predefinedEnhancementInfo?.returnTypeInfo)
|
||||
|
||||
if ((receiverTypeEnhancement?.wereChanges == true)
|
||||
|| returnTypeEnhancement.wereChanges || valueParameterEnhancements.any { it.wereChanges }) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return this.enhance(receiverTypeEnhancement?.type,
|
||||
valueParameterEnhancements.map { ValueParameterData(it.type, it.hasDefaultValue) }, returnTypeEnhancement.type) as D
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
private fun ValueParameterDescriptor.hasDefaultValueInAnnotation(type: KotlinType): Boolean {
|
||||
val defaultValue = getDefaultValueFromAnnotation()
|
||||
|
||||
return when (defaultValue) {
|
||||
is StringDefaultValue -> type.lexicalCastFrom(defaultValue.value) != null
|
||||
NullDefaultValue -> TypeUtils.acceptsNullable(type)
|
||||
null -> declaresDefaultValue()
|
||||
} && overriddenDescriptors.isEmpty()
|
||||
}
|
||||
|
||||
private inner class SignatureParts(
|
||||
private val typeContainer: Annotated?,
|
||||
private val fromOverride: KotlinType,
|
||||
private val fromOverridden: Collection<KotlinType>,
|
||||
private val isCovariant: Boolean,
|
||||
private val containerContext: LazyJavaResolverContext,
|
||||
private val containerApplicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType
|
||||
) {
|
||||
fun enhance(predefined: TypeEnhancementInfo? = null): PartEnhancementResult {
|
||||
val qualifiers = computeIndexedQualifiersForOverride()
|
||||
|
||||
val qualifiersWithPredefined: ((Int) -> JavaTypeQualifiers)? = predefined?.let {
|
||||
{ index ->
|
||||
predefined.map[index] ?: qualifiers(index)
|
||||
}
|
||||
}
|
||||
|
||||
return fromOverride.enhance(qualifiersWithPredefined ?: qualifiers)?.let { enhanced ->
|
||||
PartEnhancementResult(enhanced, wereChanges = true)
|
||||
} ?: PartEnhancementResult(fromOverride, wereChanges = false)
|
||||
}
|
||||
|
||||
private fun KotlinType.extractQualifiers(): JavaTypeQualifiers {
|
||||
val (lower, upper) =
|
||||
if (this.isFlexible())
|
||||
asFlexibleType().let { Pair(it.lowerBound, it.upperBound) }
|
||||
else Pair(this, this)
|
||||
|
||||
val mapping = JavaToKotlinClassMap
|
||||
return JavaTypeQualifiers(
|
||||
when {
|
||||
lower.isMarkedNullable -> NullabilityQualifier.NULLABLE
|
||||
!upper.isMarkedNullable -> NullabilityQualifier.NOT_NULL
|
||||
else -> null
|
||||
},
|
||||
when {
|
||||
mapping.isReadOnly(lower) -> MutabilityQualifier.READ_ONLY
|
||||
mapping.isMutable(upper) -> MutabilityQualifier.MUTABLE
|
||||
else -> null
|
||||
},
|
||||
isNotNullTypeParameter = unwrap() is NotNullTypeParameter)
|
||||
}
|
||||
|
||||
private fun KotlinType.extractQualifiersFromAnnotations(
|
||||
isHeadTypeConstructor: Boolean,
|
||||
defaultQualifiersForType: JavaTypeQualifiers?
|
||||
): JavaTypeQualifiers {
|
||||
val composedAnnotation =
|
||||
if (isHeadTypeConstructor && typeContainer != null)
|
||||
composeAnnotations(typeContainer.annotations, annotations)
|
||||
else
|
||||
annotations
|
||||
|
||||
fun <T : Any> List<FqName>.ifPresent(qualifier: T) =
|
||||
if (any { composedAnnotation.findAnnotation(it) != null }) qualifier else null
|
||||
|
||||
fun <T : Any> uniqueNotNull(x: T?, y: T?) = if (x == null || y == null || x == y) x ?: y else null
|
||||
|
||||
val defaultTypeQualifier =
|
||||
if (isHeadTypeConstructor)
|
||||
containerContext.defaultTypeQualifiers?.get(containerApplicabilityType)
|
||||
else
|
||||
defaultQualifiersForType
|
||||
|
||||
val nullabilityInfo =
|
||||
composedAnnotation.extractNullability()
|
||||
?: defaultTypeQualifier?.nullability?.let {
|
||||
NullabilityQualifierWithMigrationStatus(
|
||||
defaultTypeQualifier.nullability,
|
||||
defaultTypeQualifier.isNullabilityQualifierForWarning
|
||||
)
|
||||
}
|
||||
|
||||
return JavaTypeQualifiers(
|
||||
nullabilityInfo?.qualifier,
|
||||
uniqueNotNull(
|
||||
READ_ONLY_ANNOTATIONS.ifPresent(
|
||||
MutabilityQualifier.READ_ONLY
|
||||
),
|
||||
MUTABLE_ANNOTATIONS.ifPresent(
|
||||
MutabilityQualifier.MUTABLE
|
||||
)
|
||||
),
|
||||
isNotNullTypeParameter = nullabilityInfo?.qualifier == NullabilityQualifier.NOT_NULL && isTypeParameter(),
|
||||
isNullabilityQualifierForWarning = nullabilityInfo?.isForWarningOnly == true
|
||||
)
|
||||
}
|
||||
|
||||
private fun Annotations.extractNullability(): NullabilityQualifierWithMigrationStatus? =
|
||||
this.firstNotNullResult(this@SignatureEnhancement::extractNullability)
|
||||
|
||||
private fun computeIndexedQualifiersForOverride(): (Int) -> JavaTypeQualifiers {
|
||||
|
||||
val indexedFromSupertypes = fromOverridden.map { it.toIndexed() }
|
||||
val indexedThisType = fromOverride.toIndexed()
|
||||
|
||||
// The covariant case may be hard, e.g. in the superclass the return may be Super<T>, but in the subclass it may be Derived, which
|
||||
// is declared to extend Super<T>, and propagating data here is highly non-trivial, so we only look at the head type constructor
|
||||
// (outermost type), unless the type in the subclass is interchangeable with the all the types in superclasses:
|
||||
// e.g. we have (Mutable)List<String!>! in the subclass and { List<String!>, (Mutable)List<String>! } from superclasses
|
||||
// Note that `this` is flexible here, so it's equal to it's bounds
|
||||
val onlyHeadTypeConstructor = isCovariant && fromOverridden.any { !KotlinTypeChecker.DEFAULT.equalTypes(it, fromOverride) }
|
||||
|
||||
val treeSize = if (onlyHeadTypeConstructor) 1 else indexedThisType.size
|
||||
val computedResult = Array(treeSize) { index ->
|
||||
val isHeadTypeConstructor = index == 0
|
||||
assert(isHeadTypeConstructor || !onlyHeadTypeConstructor) { "Only head type constructors should be computed" }
|
||||
|
||||
val (qualifiers, defaultQualifiers) = indexedThisType[index]
|
||||
val verticalSlice = indexedFromSupertypes.mapNotNull { it.getOrNull(index)?.type }
|
||||
|
||||
// Only the head type constructor is safely co-variant
|
||||
qualifiers.computeQualifiersForOverride(verticalSlice, defaultQualifiers, isHeadTypeConstructor)
|
||||
}
|
||||
|
||||
return { index -> computedResult.getOrElse(index) { JavaTypeQualifiers.NONE } }
|
||||
}
|
||||
|
||||
|
||||
private fun KotlinType.toIndexed(): List<TypeAndDefaultQualifiers> {
|
||||
val list = ArrayList<TypeAndDefaultQualifiers>(1)
|
||||
|
||||
fun add(type: KotlinType, ownerContext: LazyJavaResolverContext) {
|
||||
val c = ownerContext.copyWithNewDefaultTypeQualifiers(type.annotations)
|
||||
|
||||
list.add(
|
||||
TypeAndDefaultQualifiers(
|
||||
type,
|
||||
c.defaultTypeQualifiers
|
||||
?.get(AnnotationTypeQualifierResolver.QualifierApplicabilityType.TYPE_USE)
|
||||
)
|
||||
)
|
||||
|
||||
for (arg in type.arguments) {
|
||||
if (arg.isStarProjection) {
|
||||
// TODO: sort out how to handle wildcards
|
||||
list.add(TypeAndDefaultQualifiers(arg.type, null))
|
||||
}
|
||||
else {
|
||||
add(arg.type, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add(this, containerContext)
|
||||
return list
|
||||
}
|
||||
|
||||
private fun KotlinType.computeQualifiersForOverride(
|
||||
fromSupertypes: Collection<KotlinType>,
|
||||
defaultQualifiersForType: JavaTypeQualifiers?,
|
||||
isHeadTypeConstructor: Boolean
|
||||
): JavaTypeQualifiers {
|
||||
val superQualifiers = fromSupertypes.map { it.extractQualifiers() }
|
||||
val mutabilityFromSupertypes = superQualifiers.mapNotNull { it.mutability }.toSet()
|
||||
val nullabilityFromSupertypes = superQualifiers.mapNotNull { it.nullability }.toSet()
|
||||
val nullabilityFromSupertypesWithWarning = fromSupertypes
|
||||
.mapNotNull { it.unwrapEnhancement().extractQualifiers().nullability }
|
||||
.toSet()
|
||||
|
||||
val own = extractQualifiersFromAnnotations(isHeadTypeConstructor, defaultQualifiersForType)
|
||||
val ownNullability = own.takeIf { !it.isNullabilityQualifierForWarning }?.nullability
|
||||
val ownNullabilityForWarning = own.nullability
|
||||
|
||||
val isCovariantPosition = isCovariant && isHeadTypeConstructor
|
||||
val nullability = nullabilityFromSupertypes.select(ownNullability, isCovariantPosition)
|
||||
val mutability =
|
||||
mutabilityFromSupertypes
|
||||
.select(MutabilityQualifier.MUTABLE, MutabilityQualifier.READ_ONLY, own.mutability, isCovariantPosition)
|
||||
|
||||
val canChange = ownNullabilityForWarning != ownNullability || nullabilityFromSupertypesWithWarning != nullabilityFromSupertypes
|
||||
val isAnyNonNullTypeParameter = own.isNotNullTypeParameter || superQualifiers.any { it.isNotNullTypeParameter }
|
||||
if (nullability == null && canChange) {
|
||||
val nullabilityWithWarning =
|
||||
nullabilityFromSupertypesWithWarning.select(ownNullabilityForWarning, isCovariantPosition)
|
||||
|
||||
return createJavaTypeQualifiers(
|
||||
nullabilityWithWarning, mutability,
|
||||
forWarning = true, isAnyNonNullTypeParameter = isAnyNonNullTypeParameter
|
||||
)
|
||||
}
|
||||
|
||||
return createJavaTypeQualifiers(
|
||||
nullability, mutability,
|
||||
forWarning = nullability == null,
|
||||
isAnyNonNullTypeParameter = isAnyNonNullTypeParameter
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private open class PartEnhancementResult(val type: KotlinType, val wereChanges: Boolean)
|
||||
private class ValueParameterEnhancementResult(
|
||||
type: KotlinType,
|
||||
val hasDefaultValue: Boolean,
|
||||
wereChanges: Boolean
|
||||
) : PartEnhancementResult(type, wereChanges)
|
||||
|
||||
private fun CallableMemberDescriptor.partsForValueParameter(
|
||||
// TODO: investigate if it's really can be a null (check properties' with extension overrides in Java)
|
||||
parameterDescriptor: ValueParameterDescriptor?,
|
||||
methodContext: LazyJavaResolverContext,
|
||||
collector: (CallableMemberDescriptor) -> KotlinType
|
||||
) = parts(
|
||||
parameterDescriptor, false,
|
||||
parameterDescriptor?.let { methodContext.copyWithNewDefaultTypeQualifiers(it.annotations) } ?: methodContext,
|
||||
AnnotationTypeQualifierResolver.QualifierApplicabilityType.VALUE_PARAMETER,
|
||||
collector
|
||||
)
|
||||
|
||||
private fun CallableMemberDescriptor.parts(
|
||||
typeContainer: Annotated?,
|
||||
isCovariant: Boolean,
|
||||
containerContext: LazyJavaResolverContext,
|
||||
containerApplicabilityType: AnnotationTypeQualifierResolver.QualifierApplicabilityType,
|
||||
collector: (CallableMemberDescriptor) -> KotlinType
|
||||
): SignatureParts {
|
||||
return SignatureParts(
|
||||
typeContainer,
|
||||
collector(this),
|
||||
this.overriddenDescriptors.map {
|
||||
collector(it)
|
||||
},
|
||||
isCovariant,
|
||||
// recompute default type qualifiers using type annotations
|
||||
containerContext.copyWithNewDefaultTypeQualifiers(collector(this).annotations),
|
||||
containerApplicabilityType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createJavaTypeQualifiers(
|
||||
nullability: NullabilityQualifier?,
|
||||
mutability: MutabilityQualifier?,
|
||||
forWarning: Boolean,
|
||||
isAnyNonNullTypeParameter: Boolean
|
||||
): JavaTypeQualifiers {
|
||||
if (!isAnyNonNullTypeParameter || nullability != NullabilityQualifier.NOT_NULL) {
|
||||
return JavaTypeQualifiers(nullability, mutability, false, forWarning)
|
||||
}
|
||||
return JavaTypeQualifiers(nullability, mutability, true, forWarning)
|
||||
}
|
||||
|
||||
private fun <T : Any> Set<T>.select(low: T, high: T, own: T?, isCovariant: Boolean): T? {
|
||||
if (isCovariant) {
|
||||
val supertypeQualifier = if (low in this) low else if (high in this) high else null
|
||||
return if (supertypeQualifier == low && own == high) null else own ?: supertypeQualifier
|
||||
}
|
||||
|
||||
// isInvariant
|
||||
val effectiveSet = own?.let { (this + own).toSet() } ?: this
|
||||
// if this set contains exactly one element, it is the qualifier everybody agrees upon,
|
||||
// otherwise (no qualifiers, or multiple qualifiers), there's no single such qualifier
|
||||
// and all qualifiers are discarded
|
||||
return effectiveSet.singleOrNull()
|
||||
}
|
||||
|
||||
private fun Set<NullabilityQualifier>.select(own: NullabilityQualifier?, isCovariant: Boolean) =
|
||||
if (own == NullabilityQualifier.FORCE_FLEXIBILITY)
|
||||
NullabilityQualifier.FORCE_FLEXIBILITY
|
||||
else
|
||||
select(NullabilityQualifier.NOT_NULL, NullabilityQualifier.NULLABLE, own, isCovariant)
|
||||
|
||||
private data class TypeAndDefaultQualifiers(
|
||||
val type: KotlinType,
|
||||
val defaultQualifiers: JavaTypeQualifiers?
|
||||
)
|
||||
+250
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.typeEnhancement
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.annotations.CompositeAnnotations
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.RawTypeImpl
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.MutabilityQualifier.MUTABLE
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.MutabilityQualifier.READ_ONLY
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier.NOT_NULL
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier.NULLABLE
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.createProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
|
||||
// The index in the lambda is the position of the type component:
|
||||
// Example: for `A<B, C<D, E>>`, indices go as follows: `0 - A<...>, 1 - B, 2 - C<D, E>, 3 - D, 4 - E`,
|
||||
// which corresponds to the left-to-right breadth-first walk of the tree representation of the type.
|
||||
// For flexible types, both bounds are indexed in the same way: `(A<B>..C<D>)` gives `0 - (A<B>..C<D>), 1 - B and D`.
|
||||
fun KotlinType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = unwrap().enhancePossiblyFlexible(qualifiers, 0).typeIfChanged
|
||||
|
||||
fun KotlinType.hasEnhancedNullability()
|
||||
= annotations.findAnnotation(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION) != null
|
||||
|
||||
private enum class TypeComponentPosition {
|
||||
FLEXIBLE_LOWER,
|
||||
FLEXIBLE_UPPER,
|
||||
INFLEXIBLE
|
||||
}
|
||||
|
||||
private open class Result(open val type: KotlinType, val subtreeSize: Int, val wereChanges: Boolean) {
|
||||
val typeIfChanged: KotlinType? get() = type.takeIf { wereChanges }
|
||||
}
|
||||
|
||||
private class SimpleResult(override val type: SimpleType, subtreeSize: Int, wereChanges: Boolean): Result(type, subtreeSize, wereChanges)
|
||||
|
||||
private fun UnwrappedType.enhancePossiblyFlexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int): Result {
|
||||
if (isError) return Result(this, 1, false)
|
||||
return when(this) {
|
||||
is FlexibleType -> {
|
||||
val lowerResult = lowerBound.enhanceInflexible(qualifiers, index, TypeComponentPosition.FLEXIBLE_LOWER)
|
||||
val upperResult = upperBound.enhanceInflexible(qualifiers, index, TypeComponentPosition.FLEXIBLE_UPPER)
|
||||
assert(lowerResult.subtreeSize == upperResult.subtreeSize) {
|
||||
"Different tree sizes of bounds: " +
|
||||
"lower = ($lowerBound, ${lowerResult.subtreeSize}), " +
|
||||
"upper = ($upperBound, ${upperResult.subtreeSize})"
|
||||
}
|
||||
|
||||
val wereChanges = lowerResult.wereChanges || upperResult.wereChanges
|
||||
val enhancement = lowerResult.type.getEnhancement() ?: upperResult.type.getEnhancement()
|
||||
val type = if (!wereChanges) this@enhancePossiblyFlexible
|
||||
else when {
|
||||
this is RawTypeImpl -> RawTypeImpl(lowerResult.type, upperResult.type)
|
||||
else -> KotlinTypeFactory.flexibleType(lowerResult.type, upperResult.type)
|
||||
}.wrapEnhancement(enhancement)
|
||||
|
||||
Result(
|
||||
type,
|
||||
lowerResult.subtreeSize,
|
||||
wereChanges
|
||||
)
|
||||
}
|
||||
is SimpleType -> enhanceInflexible(qualifiers, index, TypeComponentPosition.INFLEXIBLE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SimpleType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int, position: TypeComponentPosition): SimpleResult {
|
||||
val shouldEnhance = position.shouldEnhance()
|
||||
if (!shouldEnhance && arguments.isEmpty()) return SimpleResult(this, 1, false)
|
||||
|
||||
val originalClass = constructor.declarationDescriptor
|
||||
?: return SimpleResult(this, 1, false)
|
||||
|
||||
val effectiveQualifiers = qualifiers(index)
|
||||
val (enhancedClassifier, enhancedMutabilityAnnotations) = originalClass.enhanceMutability(effectiveQualifiers, position)
|
||||
|
||||
val typeConstructor = enhancedClassifier.typeConstructor
|
||||
|
||||
var globalArgIndex = index + 1
|
||||
var wereChanges = enhancedMutabilityAnnotations != null
|
||||
val enhancedArguments = arguments.mapIndexed {
|
||||
localArgIndex, arg ->
|
||||
if (arg.isStarProjection) {
|
||||
globalArgIndex++
|
||||
TypeUtils.makeStarProjection(enhancedClassifier.typeConstructor.parameters[localArgIndex])
|
||||
}
|
||||
else {
|
||||
val enhanced = arg.type.unwrap().enhancePossiblyFlexible(qualifiers, globalArgIndex)
|
||||
wereChanges = wereChanges || enhanced.wereChanges
|
||||
globalArgIndex += enhanced.subtreeSize
|
||||
createProjection(enhanced.type, arg.projectionKind, typeParameterDescriptor = typeConstructor.parameters[localArgIndex])
|
||||
}
|
||||
}
|
||||
|
||||
val (enhancedNullability, enhancedNullabilityAnnotations) = this.getEnhancedNullability(effectiveQualifiers, position)
|
||||
wereChanges = wereChanges || enhancedNullabilityAnnotations != null
|
||||
|
||||
val subtreeSize = globalArgIndex - index
|
||||
if (!wereChanges) return SimpleResult(this, subtreeSize, wereChanges = false)
|
||||
|
||||
val newAnnotations = listOf(
|
||||
annotations,
|
||||
enhancedMutabilityAnnotations,
|
||||
enhancedNullabilityAnnotations
|
||||
).filterNotNull().compositeAnnotationsOrSingle()
|
||||
|
||||
val enhancedType = KotlinTypeFactory.simpleType(
|
||||
newAnnotations,
|
||||
typeConstructor,
|
||||
enhancedArguments,
|
||||
enhancedNullability
|
||||
)
|
||||
|
||||
val enhancement = if (effectiveQualifiers.isNotNullTypeParameter) NotNullTypeParameter(enhancedType) else enhancedType
|
||||
val nullabilityForWarning = enhancedNullabilityAnnotations != null && effectiveQualifiers.isNullabilityQualifierForWarning
|
||||
val result = if (nullabilityForWarning) wrapEnhancement(enhancement) else enhancement
|
||||
|
||||
return SimpleResult(result as SimpleType, subtreeSize, wereChanges = true)
|
||||
}
|
||||
|
||||
private fun List<Annotations>.compositeAnnotationsOrSingle() = when (size) {
|
||||
0 -> error("At least one Annotations object expected")
|
||||
1 -> single()
|
||||
else -> CompositeAnnotations(this.toList())
|
||||
}
|
||||
|
||||
private fun TypeComponentPosition.shouldEnhance() = this != TypeComponentPosition.INFLEXIBLE
|
||||
|
||||
private data class EnhancementResult<out T>(val result: T, val enhancementAnnotations: Annotations?)
|
||||
private fun <T> T.noChange() = EnhancementResult(this, null)
|
||||
private fun <T> T.enhancedNullability() = EnhancementResult(this, ENHANCED_NULLABILITY_ANNOTATIONS)
|
||||
private fun <T> T.enhancedMutability() = EnhancementResult(this, ENHANCED_MUTABILITY_ANNOTATIONS)
|
||||
|
||||
private fun ClassifierDescriptor.enhanceMutability(qualifiers: JavaTypeQualifiers, position: TypeComponentPosition): EnhancementResult<ClassifierDescriptor> {
|
||||
if (!position.shouldEnhance()) return this.noChange()
|
||||
if (this !is ClassDescriptor) return this.noChange() // mutability is not applicable for type parameters
|
||||
|
||||
val mapping = JavaToKotlinClassMap
|
||||
|
||||
when (qualifiers.mutability) {
|
||||
READ_ONLY -> {
|
||||
if (position == TypeComponentPosition.FLEXIBLE_LOWER && mapping.isMutable(this)) {
|
||||
return mapping.convertMutableToReadOnly(this).enhancedMutability()
|
||||
}
|
||||
}
|
||||
MUTABLE -> {
|
||||
if (position == TypeComponentPosition.FLEXIBLE_UPPER && mapping.isReadOnly(this) ) {
|
||||
return mapping.convertReadOnlyToMutable(this).enhancedMutability()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.noChange()
|
||||
}
|
||||
|
||||
private fun KotlinType.getEnhancedNullability(qualifiers: JavaTypeQualifiers, position: TypeComponentPosition): EnhancementResult<Boolean> {
|
||||
if (!position.shouldEnhance()) return this.isMarkedNullable.noChange()
|
||||
|
||||
return when (qualifiers.nullability) {
|
||||
NULLABLE -> true.enhancedNullability()
|
||||
NOT_NULL -> false.enhancedNullability()
|
||||
else -> this.isMarkedNullable.noChange()
|
||||
}
|
||||
}
|
||||
|
||||
private val ENHANCED_NULLABILITY_ANNOTATIONS = EnhancedTypeAnnotations(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION)
|
||||
private val ENHANCED_MUTABILITY_ANNOTATIONS = EnhancedTypeAnnotations(JvmAnnotationNames.ENHANCED_MUTABILITY_ANNOTATION)
|
||||
|
||||
private class EnhancedTypeAnnotations(private val fqNameToMatch: FqName) : Annotations {
|
||||
override fun isEmpty() = false
|
||||
|
||||
override fun findAnnotation(fqName: FqName) = when (fqName) {
|
||||
fqNameToMatch -> EnhancedTypeAnnotationDescriptor
|
||||
else -> null
|
||||
}
|
||||
|
||||
override fun getAllAnnotations() = this.map { AnnotationWithTarget(it, null) }
|
||||
|
||||
override fun getUseSiteTargetedAnnotations() = emptyList<AnnotationWithTarget>()
|
||||
|
||||
// Note, that this class may break Annotations contract (!isEmpty && iterator.isEmpty())
|
||||
// It's a hack that we need unless we have stable "user data" in JetType
|
||||
override fun iterator(): Iterator<AnnotationDescriptor> = emptyList<AnnotationDescriptor>().iterator()
|
||||
}
|
||||
|
||||
private object EnhancedTypeAnnotationDescriptor : AnnotationDescriptor {
|
||||
private fun throwError(): Nothing = error("No methods should be called on this descriptor. Only its presence matters")
|
||||
override val type: KotlinType get() = throwError()
|
||||
override val allValueArguments: Map<Name, ConstantValue<*>> get() = throwError()
|
||||
override val source: SourceElement get() = throwError()
|
||||
override fun toString() = "[EnhancedType]"
|
||||
}
|
||||
|
||||
internal class NotNullTypeParameter(override val delegate: SimpleType) : CustomTypeVariable, DelegatingSimpleType() {
|
||||
|
||||
override val isTypeVariable: Boolean
|
||||
get() = true
|
||||
|
||||
override fun substitutionResult(replacement: KotlinType): KotlinType {
|
||||
val unwrappedType = replacement.unwrap()
|
||||
if (!TypeUtils.isNullableType(unwrappedType) && !unwrappedType.isTypeParameter()) return unwrappedType
|
||||
|
||||
return when (unwrappedType) {
|
||||
is SimpleType -> unwrappedType.prepareReplacement()
|
||||
is FlexibleType -> KotlinTypeFactory.flexibleType(
|
||||
unwrappedType.lowerBound.prepareReplacement(),
|
||||
unwrappedType.upperBound.prepareReplacement()
|
||||
).wrapEnhancement(unwrappedType.getEnhancement())
|
||||
else -> error("Incorrect type: $unwrappedType")
|
||||
}
|
||||
}
|
||||
|
||||
override val isMarkedNullable: Boolean
|
||||
get() = false
|
||||
|
||||
private fun SimpleType.prepareReplacement(): SimpleType {
|
||||
val result = makeNullableAsSpecified(false)
|
||||
if (!this.isTypeParameter()) return result
|
||||
|
||||
return NotNullTypeParameter(result)
|
||||
}
|
||||
|
||||
override fun replaceAnnotations(newAnnotations: Annotations) = NotNullTypeParameter(delegate.replaceAnnotations(newAnnotations))
|
||||
override fun makeNullableAsSpecified(newNullability: Boolean) =
|
||||
if (newNullability) delegate.makeNullableAsSpecified(true) else this
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.typeEnhancement
|
||||
|
||||
enum class NullabilityQualifier {
|
||||
NULLABLE,
|
||||
NOT_NULL,
|
||||
FORCE_FLEXIBILITY
|
||||
}
|
||||
|
||||
enum class MutabilityQualifier {
|
||||
READ_ONLY,
|
||||
MUTABLE
|
||||
}
|
||||
|
||||
class JavaTypeQualifiers internal constructor(
|
||||
val nullability: NullabilityQualifier?,
|
||||
val mutability: MutabilityQualifier?,
|
||||
internal val isNotNullTypeParameter: Boolean,
|
||||
internal val isNullabilityQualifierForWarning: Boolean = false
|
||||
) {
|
||||
companion object {
|
||||
val NONE = JavaTypeQualifiers(null, null, false)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.utils.extractRadix
|
||||
|
||||
sealed class JavaDefaultValue
|
||||
class EnumEntry(val descriptor: ClassDescriptor) : JavaDefaultValue()
|
||||
class Constant(val value: Any) : JavaDefaultValue()
|
||||
|
||||
fun KotlinType.lexicalCastFrom(value: String): JavaDefaultValue? {
|
||||
val typeDescriptor = constructor.declarationDescriptor
|
||||
if (typeDescriptor is ClassDescriptor && typeDescriptor.kind == ClassKind.ENUM_CLASS) {
|
||||
val descriptor = typeDescriptor.unsubstitutedInnerClassesScope.getContributedClassifier(
|
||||
Name.identifier(value),
|
||||
NoLookupLocation.FROM_BACKEND
|
||||
)
|
||||
|
||||
return if (descriptor is ClassDescriptor && descriptor.kind == ClassKind.ENUM_ENTRY) EnumEntry(descriptor) else null
|
||||
}
|
||||
|
||||
val type = this.makeNotNullable()
|
||||
val (number, radix) = extractRadix(value)
|
||||
val result: Any? = try {
|
||||
when {
|
||||
KotlinBuiltIns.isBoolean(type) -> value.toBoolean()
|
||||
KotlinBuiltIns.isChar(type) -> value.singleOrNull()
|
||||
KotlinBuiltIns.isByte(type) -> number.toByteOrNull(radix)
|
||||
KotlinBuiltIns.isShort(type) -> number.toShortOrNull(radix)
|
||||
KotlinBuiltIns.isInt(type) -> number.toIntOrNull(radix)
|
||||
KotlinBuiltIns.isLong(type) -> number.toLongOrNull(radix)
|
||||
KotlinBuiltIns.isFloat(type) -> value.toFloatOrNull()
|
||||
KotlinBuiltIns.isDouble(type) -> value.toDoubleOrNull()
|
||||
KotlinBuiltIns.isString(type) -> value
|
||||
else -> null
|
||||
}
|
||||
} catch (e: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
|
||||
return if (result != null) Constant(result) else null
|
||||
}
|
||||
+370
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.protobuf.MessageLite
|
||||
import org.jetbrains.kotlin.serialization.Flags
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.*
|
||||
import org.jetbrains.kotlin.serialization.jvm.ClassMapperLite
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.propertySignature
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.util.*
|
||||
|
||||
abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any, T : Any>(
|
||||
storageManager: StorageManager,
|
||||
private val kotlinClassFinder: KotlinClassFinder
|
||||
) : AnnotationAndConstantLoader<A, C, T> {
|
||||
private val storage = storageManager.createMemoizedFunction<KotlinJvmBinaryClass, Storage<A, C>> {
|
||||
kotlinClass ->
|
||||
loadAnnotationsAndInitializers(kotlinClass)
|
||||
}
|
||||
|
||||
protected abstract fun loadConstant(desc: String, initializer: Any): C?
|
||||
|
||||
protected abstract fun loadAnnotation(
|
||||
annotationClassId: ClassId,
|
||||
source: SourceElement,
|
||||
result: MutableList<A>
|
||||
): KotlinJvmBinaryClass.AnnotationArgumentVisitor?
|
||||
|
||||
protected abstract fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): A
|
||||
|
||||
private fun loadAnnotationIfNotSpecial(
|
||||
annotationClassId: ClassId,
|
||||
source: SourceElement,
|
||||
result: MutableList<A>
|
||||
): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
|
||||
if (annotationClassId in SPECIAL_ANNOTATIONS) return null
|
||||
|
||||
return loadAnnotation(annotationClassId, source, result)
|
||||
}
|
||||
|
||||
private fun ProtoContainer.Class.toBinaryClass(): KotlinJvmBinaryClass? =
|
||||
(source as? KotlinJvmBinarySourceElement)?.binaryClass
|
||||
|
||||
protected open fun getCachedFileContent(kotlinClass: KotlinJvmBinaryClass): ByteArray? = null
|
||||
|
||||
override fun loadClassAnnotations(container: ProtoContainer.Class): List<A> {
|
||||
val kotlinClass = container.toBinaryClass() ?: error("Class for loading annotations is not found: ${container.debugFqName()}")
|
||||
|
||||
val result = ArrayList<A>(1)
|
||||
|
||||
kotlinClass.loadClassAnnotations(object : KotlinJvmBinaryClass.AnnotationVisitor {
|
||||
override fun visitAnnotation(classId: ClassId, source: SourceElement): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
|
||||
return loadAnnotationIfNotSpecial(classId, source, result)
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
}
|
||||
}, getCachedFileContent(kotlinClass))
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun loadCallableAnnotations(container: ProtoContainer, proto: MessageLite, kind: AnnotatedCallableKind): List<T> {
|
||||
if (kind == AnnotatedCallableKind.PROPERTY) {
|
||||
proto as ProtoBuf.Property
|
||||
|
||||
val syntheticFunctionSignature = getPropertySignature(proto, container.nameResolver, container.typeTable, synthetic = true)
|
||||
val fieldSignature = getPropertySignature(proto, container.nameResolver, container.typeTable, field = true)
|
||||
|
||||
val isConst = Flags.IS_CONST.get(proto.flags)
|
||||
|
||||
val propertyAnnotations = syntheticFunctionSignature?.let { sig ->
|
||||
findClassAndLoadMemberAnnotations(container, sig, property = true, isConst = isConst)
|
||||
}.orEmpty()
|
||||
|
||||
val fieldAnnotations = fieldSignature?.let { sig ->
|
||||
findClassAndLoadMemberAnnotations(container, sig, property = true, field = true, isConst = isConst)
|
||||
}.orEmpty()
|
||||
|
||||
// TODO: check delegate presence in some other way
|
||||
return loadPropertyAnnotations(propertyAnnotations, fieldAnnotations,
|
||||
if (fieldSignature?.signature?.contains(JvmAbi.DELEGATED_PROPERTY_NAME_SUFFIX) ?: false) {
|
||||
AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD
|
||||
}
|
||||
else {
|
||||
AnnotationUseSiteTarget.FIELD
|
||||
})
|
||||
}
|
||||
|
||||
val signature = getCallableSignature(proto, container.nameResolver, container.typeTable, kind) ?: return emptyList()
|
||||
return transformAnnotations(findClassAndLoadMemberAnnotations(container, signature))
|
||||
}
|
||||
|
||||
override fun loadEnumEntryAnnotations(container: ProtoContainer, proto: ProtoBuf.EnumEntry): List<A> {
|
||||
val signature = MemberSignature.fromFieldNameAndDesc(
|
||||
container.nameResolver.getString(proto.name),
|
||||
ClassMapperLite.mapClass((container as ProtoContainer.Class).classId)
|
||||
)
|
||||
return findClassAndLoadMemberAnnotations(container, signature)
|
||||
}
|
||||
|
||||
protected abstract fun loadPropertyAnnotations(propertyAnnotations: List<A>, fieldAnnotations: List<A>,
|
||||
fieldUseSiteTarget: AnnotationUseSiteTarget): List<T>
|
||||
|
||||
protected abstract fun transformAnnotations(annotations: List<A>): List<T>
|
||||
|
||||
private fun findClassAndLoadMemberAnnotations(
|
||||
container: ProtoContainer, signature: MemberSignature,
|
||||
property: Boolean = false, field: Boolean = false, isConst: Boolean? = null
|
||||
): List<A> {
|
||||
val kotlinClass =
|
||||
findClassWithAnnotationsAndInitializers(container, getSpecialCaseContainerClass(container, property, field, isConst))
|
||||
?: return listOf()
|
||||
|
||||
return storage(kotlinClass).memberAnnotations[signature] ?: listOf()
|
||||
}
|
||||
|
||||
override fun loadValueParameterAnnotations(
|
||||
container: ProtoContainer,
|
||||
callableProto: MessageLite,
|
||||
kind: AnnotatedCallableKind,
|
||||
parameterIndex: Int,
|
||||
proto: ProtoBuf.ValueParameter
|
||||
): List<A> {
|
||||
val methodSignature = getCallableSignature(callableProto, container.nameResolver, container.typeTable, kind)
|
||||
if (methodSignature != null) {
|
||||
val index = parameterIndex + computeJvmParameterIndexShift(container, callableProto)
|
||||
val paramSignature = MemberSignature.fromMethodSignatureAndParameterIndex(methodSignature, index)
|
||||
return findClassAndLoadMemberAnnotations(container, paramSignature)
|
||||
}
|
||||
|
||||
return listOf()
|
||||
}
|
||||
|
||||
private fun computeJvmParameterIndexShift(container: ProtoContainer, message: MessageLite): Int {
|
||||
return when (message) {
|
||||
is ProtoBuf.Function -> if (message.hasReceiver()) 1 else 0
|
||||
is ProtoBuf.Property -> if (message.hasReceiver()) 1 else 0
|
||||
is ProtoBuf.Constructor -> when {
|
||||
(container as ProtoContainer.Class).kind == ProtoBuf.Class.Kind.ENUM_CLASS -> 2
|
||||
container.isInner -> 1
|
||||
else -> 0
|
||||
}
|
||||
else -> throw UnsupportedOperationException("Unsupported message: ${message::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadExtensionReceiverParameterAnnotations(
|
||||
container: ProtoContainer,
|
||||
proto: MessageLite,
|
||||
kind: AnnotatedCallableKind
|
||||
): List<A> {
|
||||
val methodSignature = getCallableSignature(proto, container.nameResolver, container.typeTable, kind)
|
||||
if (methodSignature != null) {
|
||||
val paramSignature = MemberSignature.fromMethodSignatureAndParameterIndex(methodSignature, 0)
|
||||
return findClassAndLoadMemberAnnotations(container, paramSignature)
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun loadTypeAnnotations(proto: ProtoBuf.Type, nameResolver: NameResolver): List<A> {
|
||||
return proto.getExtension(JvmProtoBuf.typeAnnotation).map { loadTypeAnnotation(it, nameResolver) }
|
||||
}
|
||||
|
||||
override fun loadTypeParameterAnnotations(proto: ProtoBuf.TypeParameter, nameResolver: NameResolver): List<A> {
|
||||
return proto.getExtension(JvmProtoBuf.typeParameterAnnotation).map { loadTypeAnnotation(it, nameResolver) }
|
||||
}
|
||||
|
||||
override fun loadPropertyConstant(container: ProtoContainer, proto: ProtoBuf.Property, expectedType: KotlinType): C? {
|
||||
val signature = getCallableSignature(proto, container.nameResolver, container.typeTable, AnnotatedCallableKind.PROPERTY)
|
||||
?: return null
|
||||
|
||||
val specialCase = getSpecialCaseContainerClass(container, property = true, field = true, isConst = Flags.IS_CONST.get(proto.flags))
|
||||
val kotlinClass = findClassWithAnnotationsAndInitializers(container, specialCase) ?: return null
|
||||
|
||||
return storage(kotlinClass).propertyConstants[signature]
|
||||
}
|
||||
|
||||
private fun findClassWithAnnotationsAndInitializers(
|
||||
container: ProtoContainer, specialCase: KotlinJvmBinaryClass?
|
||||
): KotlinJvmBinaryClass? {
|
||||
return when {
|
||||
specialCase != null -> specialCase
|
||||
container is ProtoContainer.Class -> container.toBinaryClass()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: do not use KotlinClassFinder#findKotlinClass here because it traverses the file system in the compiler
|
||||
// Introduce an API in KotlinJvmBinaryClass to find a class nearby instead
|
||||
private fun getSpecialCaseContainerClass(
|
||||
container: ProtoContainer, property: Boolean, field: Boolean, isConst: Boolean?
|
||||
): KotlinJvmBinaryClass? {
|
||||
if (property) {
|
||||
checkNotNull(isConst) { "isConst should not be null for property (container=$container)" }
|
||||
if (container is ProtoContainer.Class && container.kind == ProtoBuf.Class.Kind.INTERFACE) {
|
||||
return kotlinClassFinder.findKotlinClass(
|
||||
container.classId.createNestedClassId(Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME))
|
||||
)
|
||||
}
|
||||
if (isConst!! && container is ProtoContainer.Package) {
|
||||
// Const properties in multifile classes are generated into the facade class
|
||||
val facadeClassName = (container.source as? JvmPackagePartSource)?.facadeClassName
|
||||
if (facadeClassName != null) {
|
||||
// Converting '/' to '.' is fine here because the facade class has a top level ClassId
|
||||
return kotlinClassFinder.findKotlinClass(ClassId.topLevel(FqName(facadeClassName.internalName.replace('/', '.'))))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (field && container is ProtoContainer.Class && container.kind == ProtoBuf.Class.Kind.COMPANION_OBJECT) {
|
||||
val outerClass = container.outerClass
|
||||
if (outerClass != null && (outerClass.kind == ProtoBuf.Class.Kind.CLASS || outerClass.kind == ProtoBuf.Class.Kind.ENUM_CLASS)) {
|
||||
// Backing fields of properties of a companion object in a class are generated in the outer class
|
||||
return outerClass.toBinaryClass()
|
||||
}
|
||||
}
|
||||
if (container is ProtoContainer.Package && container.source is JvmPackagePartSource) {
|
||||
val jvmPackagePartSource = container.source as JvmPackagePartSource
|
||||
|
||||
return jvmPackagePartSource.knownJvmBinaryClass
|
||||
?: kotlinClassFinder.findKotlinClass(jvmPackagePartSource.classId)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun loadAnnotationsAndInitializers(kotlinClass: KotlinJvmBinaryClass): Storage<A, C> {
|
||||
val memberAnnotations = HashMap<MemberSignature, MutableList<A>>()
|
||||
val propertyConstants = HashMap<MemberSignature, C>()
|
||||
|
||||
kotlinClass.visitMembers(object : KotlinJvmBinaryClass.MemberVisitor {
|
||||
override fun visitMethod(name: Name, desc: String): KotlinJvmBinaryClass.MethodAnnotationVisitor? {
|
||||
return AnnotationVisitorForMethod(MemberSignature.fromMethodNameAndDesc(name.asString(), desc))
|
||||
}
|
||||
|
||||
override fun visitField(name: Name, desc: String, initializer: Any?): KotlinJvmBinaryClass.AnnotationVisitor? {
|
||||
val signature = MemberSignature.fromFieldNameAndDesc(name.asString(), desc)
|
||||
|
||||
if (initializer != null) {
|
||||
val constant = loadConstant(desc, initializer)
|
||||
if (constant != null) {
|
||||
propertyConstants[signature] = constant
|
||||
}
|
||||
}
|
||||
return MemberAnnotationVisitor(signature)
|
||||
}
|
||||
|
||||
inner class AnnotationVisitorForMethod(signature: MemberSignature) : MemberAnnotationVisitor(signature), KotlinJvmBinaryClass.MethodAnnotationVisitor {
|
||||
|
||||
override fun visitParameterAnnotation(
|
||||
index: Int, classId: ClassId, source: SourceElement
|
||||
): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
|
||||
val paramSignature = MemberSignature.fromMethodSignatureAndParameterIndex(signature, index)
|
||||
var result = memberAnnotations[paramSignature]
|
||||
if (result == null) {
|
||||
result = ArrayList<A>()
|
||||
memberAnnotations[paramSignature] = result
|
||||
}
|
||||
return loadAnnotationIfNotSpecial(classId, source, result)
|
||||
}
|
||||
}
|
||||
|
||||
open inner class MemberAnnotationVisitor(protected val signature: MemberSignature) : KotlinJvmBinaryClass.AnnotationVisitor {
|
||||
private val result = ArrayList<A>()
|
||||
|
||||
override fun visitAnnotation(classId: ClassId, source: SourceElement): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
|
||||
return loadAnnotationIfNotSpecial(classId, source, result)
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
if (result.isNotEmpty()) {
|
||||
memberAnnotations[signature] = result
|
||||
}
|
||||
}
|
||||
}
|
||||
}, getCachedFileContent(kotlinClass))
|
||||
|
||||
return Storage(memberAnnotations, propertyConstants)
|
||||
}
|
||||
|
||||
private fun getPropertySignature(
|
||||
proto: ProtoBuf.Property,
|
||||
nameResolver: NameResolver,
|
||||
typeTable: TypeTable,
|
||||
field: Boolean = false,
|
||||
synthetic: Boolean = false
|
||||
): MemberSignature? {
|
||||
val signature =
|
||||
if (proto.hasExtension(propertySignature)) proto.getExtension(propertySignature)
|
||||
else return null
|
||||
|
||||
if (field) {
|
||||
val (name, desc) = JvmProtoBufUtil.getJvmFieldSignature(proto, nameResolver, typeTable) ?: return null
|
||||
return MemberSignature.fromFieldNameAndDesc(name, desc)
|
||||
}
|
||||
else if (synthetic && signature.hasSyntheticMethod()) {
|
||||
return MemberSignature.fromMethod(nameResolver, signature.syntheticMethod)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getCallableSignature(
|
||||
proto: MessageLite,
|
||||
nameResolver: NameResolver,
|
||||
typeTable: TypeTable,
|
||||
kind: AnnotatedCallableKind
|
||||
): MemberSignature? {
|
||||
return when {
|
||||
proto is ProtoBuf.Constructor -> {
|
||||
MemberSignature.fromMethodNameAndDesc(JvmProtoBufUtil.getJvmConstructorSignature(proto, nameResolver, typeTable) ?: return null)
|
||||
}
|
||||
proto is ProtoBuf.Function -> {
|
||||
MemberSignature.fromMethodNameAndDesc(JvmProtoBufUtil.getJvmMethodSignature(proto, nameResolver, typeTable) ?: return null)
|
||||
}
|
||||
proto is ProtoBuf.Property && proto.hasExtension(propertySignature) -> {
|
||||
val signature = proto.getExtension(propertySignature)
|
||||
when (kind) {
|
||||
AnnotatedCallableKind.PROPERTY_GETTER -> MemberSignature.fromMethod(nameResolver, signature.getter)
|
||||
AnnotatedCallableKind.PROPERTY_SETTER -> MemberSignature.fromMethod(nameResolver, signature.setter)
|
||||
AnnotatedCallableKind.PROPERTY -> getPropertySignature(proto, nameResolver, typeTable, true, true)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private class Storage<out A, out C>(
|
||||
val memberAnnotations: Map<MemberSignature, List<A>>,
|
||||
val propertyConstants: Map<MemberSignature, C>
|
||||
)
|
||||
|
||||
private companion object {
|
||||
val SPECIAL_ANNOTATIONS = listOf(
|
||||
JvmAnnotationNames.METADATA_FQ_NAME,
|
||||
JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION,
|
||||
JvmAnnotationNames.JETBRAINS_NULLABLE_ANNOTATION,
|
||||
FqName("java.lang.annotation.Target"),
|
||||
FqName("java.lang.annotation.Retention"),
|
||||
FqName("java.lang.annotation.Documented")
|
||||
).map(ClassId::topLevel).toSet()
|
||||
}
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.constants.AnnotationValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.AnnotationDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.utils.compact
|
||||
import java.util.*
|
||||
|
||||
class BinaryClassAnnotationAndConstantLoaderImpl(
|
||||
private val module: ModuleDescriptor,
|
||||
private val notFoundClasses: NotFoundClasses,
|
||||
storageManager: StorageManager,
|
||||
kotlinClassFinder: KotlinClassFinder
|
||||
) : AbstractBinaryClassAnnotationAndConstantLoader<AnnotationDescriptor, ConstantValue<*>, AnnotationWithTarget>(
|
||||
storageManager, kotlinClassFinder
|
||||
) {
|
||||
private val annotationDeserializer = AnnotationDeserializer(module, notFoundClasses)
|
||||
private val factory = ConstantValueFactory(module.builtIns)
|
||||
|
||||
override fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): AnnotationDescriptor =
|
||||
annotationDeserializer.deserializeAnnotation(proto, nameResolver)
|
||||
|
||||
override fun loadConstant(desc: String, initializer: Any): ConstantValue<*>? {
|
||||
val normalizedValue: Any = if (desc in "ZBCS") {
|
||||
val intValue = initializer as Int
|
||||
when (desc) {
|
||||
"Z" -> intValue != 0
|
||||
"B" -> intValue.toByte()
|
||||
"C" -> intValue.toChar()
|
||||
"S" -> intValue.toShort()
|
||||
else -> throw AssertionError(desc)
|
||||
}
|
||||
}
|
||||
else {
|
||||
initializer
|
||||
}
|
||||
|
||||
return factory.createConstantValue(normalizedValue)
|
||||
}
|
||||
|
||||
override fun loadPropertyAnnotations(
|
||||
propertyAnnotations: List<AnnotationDescriptor>,
|
||||
fieldAnnotations: List<AnnotationDescriptor>,
|
||||
fieldUseSiteTarget: AnnotationUseSiteTarget
|
||||
): List<AnnotationWithTarget> {
|
||||
return propertyAnnotations.map { AnnotationWithTarget(it, null) } +
|
||||
fieldAnnotations.map { AnnotationWithTarget(it, fieldUseSiteTarget) }
|
||||
}
|
||||
|
||||
override fun transformAnnotations(annotations: List<AnnotationDescriptor>): List<AnnotationWithTarget> {
|
||||
return annotations.map { AnnotationWithTarget(it, null) }
|
||||
}
|
||||
|
||||
override fun loadAnnotation(
|
||||
annotationClassId: ClassId,
|
||||
source: SourceElement,
|
||||
result: MutableList<AnnotationDescriptor>
|
||||
): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
|
||||
val annotationClass = resolveClass(annotationClassId)
|
||||
|
||||
return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor {
|
||||
private val arguments = HashMap<Name, ConstantValue<*>>()
|
||||
|
||||
override fun visit(name: Name?, value: Any?) {
|
||||
if (name != null) {
|
||||
arguments[name] = createConstant(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitEnum(name: Name, enumClassId: ClassId, enumEntryName: Name) {
|
||||
arguments[name] = enumEntryValue(enumClassId, enumEntryName)
|
||||
}
|
||||
|
||||
override fun visitArray(name: Name): AnnotationArrayArgumentVisitor? {
|
||||
return object : KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor {
|
||||
private val elements = ArrayList<ConstantValue<*>>()
|
||||
|
||||
override fun visit(value: Any?) {
|
||||
elements.add(createConstant(name, value))
|
||||
}
|
||||
|
||||
override fun visitEnum(enumClassId: ClassId, enumEntryName: Name) {
|
||||
elements.add(enumEntryValue(enumClassId, enumEntryName))
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
val parameter = DescriptorResolverUtils.getAnnotationParameterByName(name, annotationClass)
|
||||
if (parameter != null) {
|
||||
arguments[name] = factory.createArrayValue(elements.compact(), parameter.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitAnnotation(name: Name, classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
|
||||
val list = ArrayList<AnnotationDescriptor>()
|
||||
val visitor = loadAnnotation(classId, SourceElement.NO_SOURCE, list)!!
|
||||
return object: KotlinJvmBinaryClass.AnnotationArgumentVisitor by visitor {
|
||||
override fun visitEnd() {
|
||||
visitor.visitEnd()
|
||||
arguments[name] = AnnotationValue(list.single())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: see analogous code in AnnotationDeserializer
|
||||
private fun enumEntryValue(enumClassId: ClassId, name: Name): ConstantValue<*> {
|
||||
val enumClass = resolveClass(enumClassId)
|
||||
if (enumClass.kind == ClassKind.ENUM_CLASS) {
|
||||
val classifier = enumClass.unsubstitutedInnerClassesScope.getContributedClassifier(name, NoLookupLocation.FROM_JAVA_LOADER)
|
||||
if (classifier is ClassDescriptor) {
|
||||
return factory.createEnumValue(classifier)
|
||||
}
|
||||
}
|
||||
return factory.createErrorValue("Unresolved enum entry: $enumClassId.$name")
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
result.add(AnnotationDescriptorImpl(annotationClass.defaultType, arguments, source))
|
||||
}
|
||||
|
||||
private fun createConstant(name: Name?, value: Any?): ConstantValue<*> {
|
||||
return factory.createConstantValue(value) ?:
|
||||
factory.createErrorValue("Unsupported annotation argument: $name")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveClass(classId: ClassId): ClassDescriptor {
|
||||
return module.findNonGenericClassAcrossDependencies(classId, notFoundClasses)
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.NotFoundClasses
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.AdditionalClassPartsProvider
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclarationFilter
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaPackageFragmentProvider
|
||||
import org.jetbrains.kotlin.platform.JvmBuiltIns
|
||||
import org.jetbrains.kotlin.serialization.deserialization.*
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
// This class is needed only for easier injection: exact types of needed components are specified in the constructor here.
|
||||
// Otherwise injector generator is not smart enough to deduce, for example, which package fragment provider DeserializationComponents needs
|
||||
class DeserializationComponentsForJava(
|
||||
storageManager: StorageManager,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
configuration: DeserializationConfiguration,
|
||||
classDataFinder: JavaClassDataFinder,
|
||||
annotationAndConstantLoader: BinaryClassAnnotationAndConstantLoaderImpl,
|
||||
packageFragmentProvider: LazyJavaPackageFragmentProvider,
|
||||
notFoundClasses: NotFoundClasses,
|
||||
errorReporter: ErrorReporter,
|
||||
lookupTracker: LookupTracker,
|
||||
contractDeserializer: ContractDeserializer
|
||||
) {
|
||||
val components: DeserializationComponents
|
||||
|
||||
init {
|
||||
// currently built-ins may be not an instance of JvmBuiltIns only in case of built-ins serialization
|
||||
val jvmBuiltIns = moduleDescriptor.builtIns as? JvmBuiltIns
|
||||
components = DeserializationComponents(
|
||||
storageManager, moduleDescriptor, configuration, classDataFinder, annotationAndConstantLoader, packageFragmentProvider,
|
||||
LocalClassifierTypeSettings.Default, errorReporter, lookupTracker, JavaFlexibleTypeDeserializer,
|
||||
emptyList(), notFoundClasses, contractDeserializer,
|
||||
additionalClassPartsProvider = jvmBuiltIns?.settings ?: AdditionalClassPartsProvider.None,
|
||||
platformDependentDeclarationFilter = jvmBuiltIns?.settings ?: PlatformDependentDeclarationFilter.NoPlatformDependent
|
||||
)
|
||||
}
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.serialization.ClassDataWithSource
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
|
||||
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||
import javax.inject.Inject
|
||||
|
||||
class DeserializedDescriptorResolver {
|
||||
lateinit var components: DeserializationComponents
|
||||
|
||||
// component dependency cycle
|
||||
@Inject
|
||||
fun setComponents(components: DeserializationComponentsForJava) {
|
||||
this.components = components.components
|
||||
}
|
||||
|
||||
private val skipMetadataVersionCheck: Boolean
|
||||
get() = components.configuration.skipMetadataVersionCheck
|
||||
|
||||
fun resolveClass(kotlinClass: KotlinJvmBinaryClass): ClassDescriptor? {
|
||||
val classData = readClassData(kotlinClass) ?: return null
|
||||
return components.classDeserializer.deserializeClass(kotlinClass.classId, classData)
|
||||
}
|
||||
|
||||
internal fun readClassData(kotlinClass: KotlinJvmBinaryClass): ClassDataWithSource? {
|
||||
val data = readData(kotlinClass, KOTLIN_CLASS) ?: return null
|
||||
val strings = kotlinClass.classHeader.strings ?: return null
|
||||
val classData = parseProto(kotlinClass) {
|
||||
JvmProtoBufUtil.readClassDataFrom(data, strings)
|
||||
} ?: return null
|
||||
val source = KotlinJvmBinarySourceElement(kotlinClass, kotlinClass.incompatibility, kotlinClass.isPreReleaseInvisible)
|
||||
return ClassDataWithSource(classData, source)
|
||||
}
|
||||
|
||||
fun createKotlinPackagePartScope(descriptor: PackageFragmentDescriptor, kotlinClass: KotlinJvmBinaryClass): MemberScope? {
|
||||
val data = readData(kotlinClass, KOTLIN_FILE_FACADE_OR_MULTIFILE_CLASS_PART) ?: return null
|
||||
val strings = kotlinClass.classHeader.strings ?: return null
|
||||
val (nameResolver, packageProto) = parseProto(kotlinClass) {
|
||||
JvmProtoBufUtil.readPackageDataFrom(data, strings)
|
||||
} ?: return null
|
||||
val source = JvmPackagePartSource(kotlinClass, kotlinClass.incompatibility, kotlinClass.isPreReleaseInvisible)
|
||||
return DeserializedPackageMemberScope(descriptor, packageProto, nameResolver, source, components) {
|
||||
// All classes are included into Java scope
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private val KotlinJvmBinaryClass.incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>?
|
||||
get() {
|
||||
if (skipMetadataVersionCheck || classHeader.metadataVersion.isCompatible()) return null
|
||||
return IncompatibleVersionErrorData(classHeader.metadataVersion, JvmMetadataVersion.INSTANCE, location, classId)
|
||||
}
|
||||
|
||||
private val KotlinJvmBinaryClass.isPreReleaseInvisible: Boolean
|
||||
get() = !components.configuration.skipPreReleaseCheck &&
|
||||
!KotlinCompilerVersion.isPreRelease() &&
|
||||
(classHeader.isPreRelease || classHeader.metadataVersion == KOTLIN_1_1_EAP_METADATA_VERSION)
|
||||
|
||||
internal fun readData(kotlinClass: KotlinJvmBinaryClass, expectedKinds: Set<KotlinClassHeader.Kind>): Array<String>? {
|
||||
val header = kotlinClass.classHeader
|
||||
return (header.data ?: header.incompatibleData)?.takeIf { header.kind in expectedKinds }
|
||||
}
|
||||
|
||||
private inline fun <T : Any> parseProto(klass: KotlinJvmBinaryClass, block: () -> T): T? {
|
||||
try {
|
||||
try {
|
||||
return block()
|
||||
}
|
||||
catch (e: InvalidProtocolBufferException) {
|
||||
throw IllegalStateException("Could not read data from ${klass.location}", e)
|
||||
}
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
if (skipMetadataVersionCheck || klass.classHeader.metadataVersion.isCompatible()) {
|
||||
throw e
|
||||
}
|
||||
|
||||
// TODO: log.warn
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal val KOTLIN_CLASS = setOf(KotlinClassHeader.Kind.CLASS)
|
||||
|
||||
private val KOTLIN_FILE_FACADE_OR_MULTIFILE_CLASS_PART =
|
||||
setOf(KotlinClassHeader.Kind.FILE_FACADE, KotlinClassHeader.Kind.MULTIFILE_CLASS_PART)
|
||||
|
||||
private val KOTLIN_1_1_EAP_METADATA_VERSION = JvmMetadataVersion(1, 1, 2)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.serialization.ClassDataWithSource
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
|
||||
|
||||
class JavaClassDataFinder(
|
||||
internal val kotlinClassFinder: KotlinClassFinder,
|
||||
private val deserializedDescriptorResolver: DeserializedDescriptorResolver
|
||||
) : ClassDataFinder {
|
||||
override fun findClassData(classId: ClassId): ClassDataWithSource? {
|
||||
val kotlinClass = kotlinClassFinder.findKotlinClass(classId) ?: return null
|
||||
assert(kotlinClass.classId == classId) {
|
||||
"Class with incorrect id found: expected $classId, actual ${kotlinClass.classId}"
|
||||
}
|
||||
return deserializedDescriptorResolver.readClassData(kotlinClass)
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.RawTypeImpl
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
|
||||
object JavaFlexibleTypeDeserializer : FlexibleTypeDeserializer {
|
||||
val id = "kotlin.jvm.PlatformType"
|
||||
|
||||
override fun create(proto: ProtoBuf.Type, flexibleId: String, lowerBound: SimpleType, upperBound: SimpleType): KotlinType {
|
||||
if (flexibleId != id) return ErrorUtils.createErrorType("Error java flexible type with id: $flexibleId. ($lowerBound..$upperBound)")
|
||||
if (proto.hasExtension(JvmProtoBuf.isRaw)) {
|
||||
return RawTypeImpl(lowerBound, upperBound)
|
||||
}
|
||||
return KotlinTypeFactory.flexibleType(lowerBound, upperBound)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,497 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.builtins.BuiltInsInitializer
|
||||
import org.jetbrains.kotlin.builtins.CloneableClassScope
|
||||
import org.jetbrains.kotlin.builtins.JvmBuiltInClassDescriptorFactory
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
|
||||
import org.jetbrains.kotlin.descriptors.annotations.createDeprecatedAnnotation
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.AdditionalClassPartsProvider
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclarationFilter
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.components.JavaResolverCache
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaClassDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.platform.createMappedTypeParametersSubstitution
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.LazyWrappedType
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
import java.io.Serializable
|
||||
import java.util.*
|
||||
|
||||
open class JvmBuiltInsSettings(
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
storageManager: StorageManager,
|
||||
deferredOwnerModuleDescriptor: () -> ModuleDescriptor,
|
||||
isAdditionalBuiltInsFeatureSupported: () -> Boolean
|
||||
) : AdditionalClassPartsProvider, PlatformDependentDeclarationFilter {
|
||||
private val j2kClassMap = JavaToKotlinClassMap
|
||||
|
||||
private val ownerModuleDescriptor: ModuleDescriptor by lazy(deferredOwnerModuleDescriptor)
|
||||
private val isAdditionalBuiltInsFeatureSupported: Boolean by lazy(isAdditionalBuiltInsFeatureSupported)
|
||||
|
||||
private val mockSerializableType = storageManager.createMockJavaIoSerializableType()
|
||||
private val cloneableType by storageManager.createLazyValue {
|
||||
ownerModuleDescriptor.findNonGenericClassAcrossDependencies(
|
||||
JvmBuiltInClassDescriptorFactory.CLONEABLE_CLASS_ID,
|
||||
NotFoundClasses(storageManager, ownerModuleDescriptor)
|
||||
).defaultType
|
||||
}
|
||||
|
||||
private val javaAnalogueClassesWithCustomSupertypeCache = storageManager.createCacheWithNotNullValues<FqName, ClassDescriptor>()
|
||||
|
||||
// Most this properties are lazy because they depends on KotlinBuiltIns initialization that depends on JvmBuiltInsSettings object
|
||||
private val notConsideredDeprecation by storageManager.createLazyValue {
|
||||
moduleDescriptor.builtIns.createDeprecatedAnnotation(
|
||||
"This member is not fully supported by Kotlin compiler, so it may be absent or have different signature in next major version"
|
||||
).let { AnnotationsImpl(listOf(it)) }
|
||||
}
|
||||
|
||||
private fun StorageManager.createMockJavaIoSerializableType(): KotlinType {
|
||||
val mockJavaIoPackageFragment = object : PackageFragmentDescriptorImpl(moduleDescriptor, FqName("java.io")) {
|
||||
override fun getMemberScope() = MemberScope.Empty
|
||||
}
|
||||
|
||||
//NOTE: can't reference anyType right away, because this is sometimes called when JvmBuiltIns are initializing
|
||||
val superTypes = listOf(LazyWrappedType(this) { moduleDescriptor.builtIns.anyType })
|
||||
|
||||
val mockSerializableClass = ClassDescriptorImpl(
|
||||
mockJavaIoPackageFragment, Name.identifier("Serializable"), Modality.ABSTRACT, ClassKind.INTERFACE, superTypes,
|
||||
SourceElement.NO_SOURCE, /* isExternal = */ false
|
||||
)
|
||||
|
||||
mockSerializableClass.initialize(MemberScope.Empty, emptySet(), null)
|
||||
return mockSerializableClass.defaultType
|
||||
}
|
||||
|
||||
override fun getSupertypes(classDescriptor: ClassDescriptor): Collection<KotlinType> {
|
||||
val fqName = classDescriptor.fqNameUnsafe
|
||||
return when {
|
||||
isArrayOrPrimitiveArray(fqName) -> listOf(cloneableType, mockSerializableType)
|
||||
isSerializableInJava(fqName) -> listOf(mockSerializableType)
|
||||
else -> listOf()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFunctions(name: Name, classDescriptor: ClassDescriptor): Collection<SimpleFunctionDescriptor> {
|
||||
if (name == CloneableClassScope.CLONE_NAME && classDescriptor is DeserializedClassDescriptor &&
|
||||
KotlinBuiltIns.isArrayOrPrimitiveArray(classDescriptor)) {
|
||||
// Do not create clone for arrays deserialized from metadata in the old (1.0) runtime, because clone is declared there anyway
|
||||
if (classDescriptor.classProto.functionList.any { functionProto ->
|
||||
classDescriptor.c.nameResolver.getName(functionProto.name) == CloneableClassScope.CLONE_NAME
|
||||
}) {
|
||||
return emptyList()
|
||||
}
|
||||
return listOf(createCloneForArray(
|
||||
classDescriptor, cloneableType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS).single()
|
||||
))
|
||||
}
|
||||
|
||||
if (!isAdditionalBuiltInsFeatureSupported) return emptyList()
|
||||
|
||||
return getAdditionalFunctions(classDescriptor) {
|
||||
it.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS)
|
||||
}.mapNotNull {
|
||||
additionalMember ->
|
||||
val substitutedWithKotlinTypeParameters =
|
||||
additionalMember.substitute(
|
||||
createMappedTypeParametersSubstitution(
|
||||
additionalMember.containingDeclaration as ClassDescriptor, classDescriptor).buildSubstitutor()
|
||||
) as SimpleFunctionDescriptor
|
||||
|
||||
substitutedWithKotlinTypeParameters.newCopyBuilder().apply {
|
||||
setOwner(classDescriptor)
|
||||
setDispatchReceiverParameter(classDescriptor.thisAsReceiverParameter)
|
||||
setPreserveSourceElement()
|
||||
setSubstitution(UnsafeVarianceTypeSubstitution(moduleDescriptor.builtIns))
|
||||
|
||||
val memberStatus = additionalMember.getJdkMethodStatus()
|
||||
when (memberStatus) {
|
||||
JDKMemberStatus.BLACK_LIST -> {
|
||||
// Black list methods in final class can't be overridden or called with 'super'
|
||||
if (classDescriptor.isFinalClass) return@mapNotNull null
|
||||
setHiddenForResolutionEverywhereBesideSupercalls()
|
||||
}
|
||||
|
||||
JDKMemberStatus.NOT_CONSIDERED -> {
|
||||
setAdditionalAnnotations(notConsideredDeprecation)
|
||||
}
|
||||
|
||||
JDKMemberStatus.DROP -> return@mapNotNull null
|
||||
|
||||
JDKMemberStatus.WHITE_LIST -> Unit // Do nothing
|
||||
}
|
||||
|
||||
}.build()!!
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFunctionsNames(classDescriptor: ClassDescriptor): Set<Name> {
|
||||
if (!isAdditionalBuiltInsFeatureSupported) return emptySet()
|
||||
// NB: It's just an approximation that could be calculated relatively fast
|
||||
// More precise computation would look like `getAdditionalFunctions` (and the measurements show that it would be rather slow)
|
||||
return classDescriptor.getJavaAnalogue()?.unsubstitutedMemberScope?.getFunctionNames() ?: emptySet()
|
||||
}
|
||||
|
||||
private fun getAdditionalFunctions(
|
||||
classDescriptor: ClassDescriptor,
|
||||
functionsByScope: (MemberScope) -> Collection<SimpleFunctionDescriptor>
|
||||
): Collection<SimpleFunctionDescriptor> {
|
||||
val javaAnalogueDescriptor = classDescriptor.getJavaAnalogue() ?: return emptyList()
|
||||
|
||||
val kotlinClassDescriptors = j2kClassMap.mapPlatformClass(javaAnalogueDescriptor.fqNameSafe, FallbackBuiltIns.Instance)
|
||||
val kotlinMutableClassIfContainer = kotlinClassDescriptors.lastOrNull() ?: return emptyList()
|
||||
val kotlinVersions = SmartSet.create(kotlinClassDescriptors.map { it.fqNameSafe })
|
||||
|
||||
val isMutable = j2kClassMap.isMutable(classDescriptor)
|
||||
|
||||
val fakeJavaClassDescriptor = javaAnalogueClassesWithCustomSupertypeCache.computeIfAbsent(javaAnalogueDescriptor.fqNameSafe) {
|
||||
javaAnalogueDescriptor.copy(
|
||||
javaResolverCache = JavaResolverCache.EMPTY,
|
||||
additionalSupertypeClassDescriptor = kotlinMutableClassIfContainer)
|
||||
}
|
||||
|
||||
val scope = fakeJavaClassDescriptor.unsubstitutedMemberScope
|
||||
|
||||
return functionsByScope(scope)
|
||||
.filter { analogueMember ->
|
||||
if (analogueMember.kind != CallableMemberDescriptor.Kind.DECLARATION) return@filter false
|
||||
if (!analogueMember.visibility.isPublicAPI) return@filter false
|
||||
if (KotlinBuiltIns.isDeprecated(analogueMember)) return@filter false
|
||||
|
||||
if (analogueMember.overriddenDescriptors.any {
|
||||
it.containingDeclaration.fqNameSafe in kotlinVersions
|
||||
}) return@filter false
|
||||
|
||||
!analogueMember.isMutabilityViolation(isMutable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCloneForArray(
|
||||
arrayClassDescriptor: DeserializedClassDescriptor,
|
||||
cloneFromCloneable: SimpleFunctionDescriptor
|
||||
): SimpleFunctionDescriptor = cloneFromCloneable.newCopyBuilder().apply {
|
||||
setOwner(arrayClassDescriptor)
|
||||
setVisibility(Visibilities.PUBLIC)
|
||||
setReturnType(arrayClassDescriptor.defaultType)
|
||||
setDispatchReceiverParameter(arrayClassDescriptor.thisAsReceiverParameter)
|
||||
}.build()!!
|
||||
|
||||
private fun SimpleFunctionDescriptor.isMutabilityViolation(isMutable: Boolean): Boolean {
|
||||
val owner = containingDeclaration as ClassDescriptor
|
||||
val jvmDescriptor = computeJvmDescriptor()
|
||||
|
||||
if ((SignatureBuildingComponents.signature(owner, jvmDescriptor) in MUTABLE_METHOD_SIGNATURES) xor isMutable) return true
|
||||
|
||||
return DFS.ifAny<CallableMemberDescriptor>(
|
||||
listOf(this),
|
||||
{ it.original.overriddenDescriptors }
|
||||
) {
|
||||
overridden ->
|
||||
overridden.kind == CallableMemberDescriptor.Kind.DECLARATION &&
|
||||
j2kClassMap.isMutable(overridden.containingDeclaration as ClassDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.getJdkMethodStatus(): JDKMemberStatus {
|
||||
val owner = containingDeclaration as ClassDescriptor
|
||||
val jvmDescriptor = computeJvmDescriptor()
|
||||
var result: JDKMemberStatus? = null
|
||||
return DFS.dfs<ClassDescriptor, JDKMemberStatus>(
|
||||
listOf(owner),
|
||||
{
|
||||
// Search through mapped supertypes to determine that Set.toArray is in blacklist, while we have only
|
||||
// Collection.toArray there explicitly
|
||||
// Note, that we can't find j.u.Collection.toArray within overriddenDescriptors of j.u.Set.toArray
|
||||
it.typeConstructor.supertypes.mapNotNull {
|
||||
(it.constructor.declarationDescriptor?.original as? ClassDescriptor)?.getJavaAnalogue()
|
||||
}
|
||||
},
|
||||
object : DFS.AbstractNodeHandler<ClassDescriptor, JDKMemberStatus>() {
|
||||
override fun beforeChildren(javaClassDescriptor: ClassDescriptor): Boolean {
|
||||
val signature = SignatureBuildingComponents.signature(javaClassDescriptor, jvmDescriptor)
|
||||
when (signature) {
|
||||
in BLACK_LIST_METHOD_SIGNATURES -> { result = JDKMemberStatus.BLACK_LIST }
|
||||
in WHITE_LIST_METHOD_SIGNATURES -> { result = JDKMemberStatus.WHITE_LIST }
|
||||
in DROP_LIST_METHOD_SIGNATURES -> { result = JDKMemberStatus.DROP }
|
||||
}
|
||||
|
||||
return result == null
|
||||
}
|
||||
|
||||
override fun result() = result ?: JDKMemberStatus.NOT_CONSIDERED
|
||||
})
|
||||
}
|
||||
|
||||
private enum class JDKMemberStatus {
|
||||
BLACK_LIST, WHITE_LIST, NOT_CONSIDERED, DROP
|
||||
}
|
||||
|
||||
private fun ClassDescriptor.getJavaAnalogue(): LazyJavaClassDescriptor? {
|
||||
// Prevents recursive dependency: memberScope(Any) -> memberScope(Object) -> memberScope(Any)
|
||||
// No additional members should be added to Any
|
||||
if (KotlinBuiltIns.isAny(this)) return null
|
||||
|
||||
// Optimization: only classes under kotlin.* can have Java analogues
|
||||
if (!KotlinBuiltIns.isUnderKotlinPackage(this)) return null
|
||||
|
||||
val fqName = fqNameUnsafe
|
||||
if (!fqName.isSafe) return null
|
||||
val javaAnalogueFqName = j2kClassMap.mapKotlinToJava(fqName)?.asSingleFqName() ?: return null
|
||||
|
||||
return ownerModuleDescriptor.resolveClassByFqName(javaAnalogueFqName, NoLookupLocation.FROM_BUILTINS) as? LazyJavaClassDescriptor
|
||||
}
|
||||
|
||||
override fun getConstructors(classDescriptor: ClassDescriptor): Collection<ClassConstructorDescriptor> {
|
||||
if (classDescriptor.kind != ClassKind.CLASS || !isAdditionalBuiltInsFeatureSupported) return emptyList()
|
||||
|
||||
val javaAnalogueDescriptor = classDescriptor.getJavaAnalogue() ?: return emptyList()
|
||||
|
||||
val defaultKotlinVersion =
|
||||
j2kClassMap.mapJavaToKotlin(javaAnalogueDescriptor.fqNameSafe, FallbackBuiltIns.Instance) ?: return emptyList()
|
||||
|
||||
val substitutor = createMappedTypeParametersSubstitution(defaultKotlinVersion, javaAnalogueDescriptor).buildSubstitutor()
|
||||
|
||||
fun ConstructorDescriptor.isEffectivelyTheSameAs(javaConstructor: ConstructorDescriptor) =
|
||||
OverridingUtil.getBothWaysOverridability(this, javaConstructor.substitute(substitutor)) ==
|
||||
OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE
|
||||
|
||||
return javaAnalogueDescriptor.constructors.filter {
|
||||
javaConstructor ->
|
||||
javaConstructor.visibility.isPublicAPI &&
|
||||
defaultKotlinVersion.constructors.none { it.isEffectivelyTheSameAs(javaConstructor) } &&
|
||||
!javaConstructor.isTrivialCopyConstructorFor(classDescriptor) &&
|
||||
!KotlinBuiltIns.isDeprecated(javaConstructor) &&
|
||||
SignatureBuildingComponents.signature(javaAnalogueDescriptor, javaConstructor.computeJvmDescriptor()) !in BLACK_LIST_CONSTRUCTOR_SIGNATURES
|
||||
}.map {
|
||||
javaConstructor ->
|
||||
javaConstructor.newCopyBuilder().apply {
|
||||
setOwner(classDescriptor)
|
||||
setReturnType(classDescriptor.defaultType)
|
||||
setPreserveSourceElement()
|
||||
setSubstitution(substitutor.substitution)
|
||||
if (SignatureBuildingComponents.signature(javaAnalogueDescriptor, javaConstructor.computeJvmDescriptor()) !in WHITE_LIST_CONSTRUCTOR_SIGNATURES) {
|
||||
setAdditionalAnnotations(notConsideredDeprecation)
|
||||
}
|
||||
|
||||
}.build() as ClassConstructorDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
override fun isFunctionAvailable(classDescriptor: ClassDescriptor, functionDescriptor: SimpleFunctionDescriptor): Boolean {
|
||||
val javaAnalogueClassDescriptor = classDescriptor.getJavaAnalogue() ?: return true
|
||||
|
||||
if (!functionDescriptor.annotations.hasAnnotation(PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME)) return true
|
||||
if (!isAdditionalBuiltInsFeatureSupported) return false
|
||||
|
||||
val jvmDescriptor = functionDescriptor.computeJvmDescriptor()
|
||||
return javaAnalogueClassDescriptor
|
||||
.unsubstitutedMemberScope
|
||||
.getContributedFunctions(functionDescriptor.name, NoLookupLocation.FROM_BUILTINS)
|
||||
.any { it.computeJvmDescriptor() == jvmDescriptor }
|
||||
}
|
||||
|
||||
private fun ConstructorDescriptor.isTrivialCopyConstructorFor(classDescriptor: ClassDescriptor): Boolean =
|
||||
valueParameters.size == 1 &&
|
||||
valueParameters.single().type.constructor.declarationDescriptor?.fqNameUnsafe == classDescriptor.fqNameUnsafe
|
||||
|
||||
companion object {
|
||||
fun isSerializableInJava(fqName: FqNameUnsafe): Boolean {
|
||||
if (isArrayOrPrimitiveArray(fqName)) {
|
||||
return true
|
||||
}
|
||||
val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(fqName) ?: return false
|
||||
val classViaReflection = try {
|
||||
Class.forName(javaClassId.asSingleFqName().asString())
|
||||
}
|
||||
catch (e: ClassNotFoundException) {
|
||||
return false
|
||||
}
|
||||
return Serializable::class.java.isAssignableFrom(classViaReflection)
|
||||
}
|
||||
|
||||
private fun isArrayOrPrimitiveArray(fqName: FqNameUnsafe): Boolean {
|
||||
return fqName == KotlinBuiltIns.FQ_NAMES.array || KotlinBuiltIns.isPrimitiveArray(fqName)
|
||||
}
|
||||
|
||||
val DROP_LIST_METHOD_SIGNATURES: Set<String> =
|
||||
SignatureBuildingComponents.inJavaUtil(
|
||||
"Collection",
|
||||
"toArray()[Ljava/lang/Object;", "toArray([Ljava/lang/Object;)[Ljava/lang/Object;") +
|
||||
|
||||
"java/lang/annotation/Annotation.annotationType()Ljava/lang/Class;"
|
||||
|
||||
val BLACK_LIST_METHOD_SIGNATURES: Set<String> =
|
||||
signatures {
|
||||
buildPrimitiveValueMethodsSet() +
|
||||
|
||||
inJavaUtil("List", "sort(Ljava/util/Comparator;)V") +
|
||||
|
||||
inJavaLang("String",
|
||||
"codePointAt(I)I", "codePointBefore(I)I", "codePointCount(II)I", "compareToIgnoreCase(Ljava/lang/String;)I",
|
||||
"concat(Ljava/lang/String;)Ljava/lang/String;", "contains(Ljava/lang/CharSequence;)Z",
|
||||
"contentEquals(Ljava/lang/CharSequence;)Z", "contentEquals(Ljava/lang/StringBuffer;)Z",
|
||||
"endsWith(Ljava/lang/String;)Z", "equalsIgnoreCase(Ljava/lang/String;)Z", "getBytes()[B", "getBytes(II[BI)V",
|
||||
"getBytes(Ljava/lang/String;)[B", "getBytes(Ljava/nio/charset/Charset;)[B", "getChars(II[CI)V",
|
||||
"indexOf(I)I", "indexOf(II)I", "indexOf(Ljava/lang/String;)I", "indexOf(Ljava/lang/String;I)I",
|
||||
"intern()Ljava/lang/String;", "isEmpty()Z", "lastIndexOf(I)I", "lastIndexOf(II)I",
|
||||
"lastIndexOf(Ljava/lang/String;)I", "lastIndexOf(Ljava/lang/String;I)I", "matches(Ljava/lang/String;)Z",
|
||||
"offsetByCodePoints(II)I", "regionMatches(ILjava/lang/String;II)Z", "regionMatches(ZILjava/lang/String;II)Z",
|
||||
"replaceAll(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", "replace(CC)Ljava/lang/String;",
|
||||
"replaceFirst(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
|
||||
"replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;",
|
||||
"split(Ljava/lang/String;I)[Ljava/lang/String;", "split(Ljava/lang/String;)[Ljava/lang/String;",
|
||||
"startsWith(Ljava/lang/String;I)Z", "startsWith(Ljava/lang/String;)Z", "substring(II)Ljava/lang/String;",
|
||||
"substring(I)Ljava/lang/String;", "toCharArray()[C", "toLowerCase()Ljava/lang/String;",
|
||||
"toLowerCase(Ljava/util/Locale;)Ljava/lang/String;", "toUpperCase()Ljava/lang/String;",
|
||||
"toUpperCase(Ljava/util/Locale;)Ljava/lang/String;", "trim()Ljava/lang/String;") +
|
||||
|
||||
inJavaLang("Double", "isInfinite()Z", "isNaN()Z") +
|
||||
inJavaLang("Float", "isInfinite()Z", "isNaN()Z") +
|
||||
|
||||
inJavaLang("Enum", "getDeclaringClass()Ljava/lang/Class;", "finalize()V")
|
||||
}
|
||||
|
||||
private fun buildPrimitiveValueMethodsSet(): Set<String> =
|
||||
signatures {
|
||||
listOf(JvmPrimitiveType.BOOLEAN, JvmPrimitiveType.CHAR).flatMapTo(LinkedHashSet()) {
|
||||
inJavaLang(it.wrapperFqName.shortName().asString(), "${it.javaKeywordName}Value()${it.desc}")
|
||||
}
|
||||
}
|
||||
|
||||
val WHITE_LIST_METHOD_SIGNATURES: Set<String> =
|
||||
signatures {
|
||||
inJavaLang("CharSequence",
|
||||
"codePoints()Ljava/util/stream/IntStream;", "chars()Ljava/util/stream/IntStream;") +
|
||||
|
||||
inJavaUtil("Iterator",
|
||||
"forEachRemaining(Ljava/util/function/Consumer;)V") +
|
||||
|
||||
inJavaLang("Iterable",
|
||||
"forEach(Ljava/util/function/Consumer;)V", "spliterator()Ljava/util/Spliterator;") +
|
||||
|
||||
inJavaLang("Throwable",
|
||||
"setStackTrace([Ljava/lang/StackTraceElement;)V", "fillInStackTrace()Ljava/lang/Throwable;",
|
||||
"getLocalizedMessage()Ljava/lang/String;", "printStackTrace()V", "printStackTrace(Ljava/io/PrintStream;)V",
|
||||
"printStackTrace(Ljava/io/PrintWriter;)V", "getStackTrace()[Ljava/lang/StackTraceElement;",
|
||||
"initCause(Ljava/lang/Throwable;)Ljava/lang/Throwable;", "getSuppressed()[Ljava/lang/Throwable;",
|
||||
"addSuppressed(Ljava/lang/Throwable;)V") +
|
||||
|
||||
inJavaUtil("Collection",
|
||||
"spliterator()Ljava/util/Spliterator;", "parallelStream()Ljava/util/stream/Stream;",
|
||||
"stream()Ljava/util/stream/Stream;", "removeIf(Ljava/util/function/Predicate;)Z") +
|
||||
|
||||
inJavaUtil("List",
|
||||
"replaceAll(Ljava/util/function/UnaryOperator;)V") +
|
||||
|
||||
inJavaUtil("Map",
|
||||
"getOrDefault(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
"forEach(Ljava/util/function/BiConsumer;)V", "replaceAll(Ljava/util/function/BiFunction;)V",
|
||||
"merge(Ljava/lang/Object;Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;",
|
||||
"computeIfPresent(Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;",
|
||||
"putIfAbsent(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
"replace(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Z",
|
||||
"replace(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
"computeIfAbsent(Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object;",
|
||||
"compute(Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;")
|
||||
}
|
||||
|
||||
val MUTABLE_METHOD_SIGNATURES: Set<String> =
|
||||
signatures {
|
||||
inJavaUtil("Collection", "removeIf(Ljava/util/function/Predicate;)Z") +
|
||||
|
||||
inJavaUtil("List", "replaceAll(Ljava/util/function/UnaryOperator;)V", "sort(Ljava/util/Comparator;)V") +
|
||||
|
||||
inJavaUtil("Map",
|
||||
"computeIfAbsent(Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object;",
|
||||
"computeIfPresent(Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;",
|
||||
"compute(Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;",
|
||||
"merge(Ljava/lang/Object;Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;",
|
||||
"putIfAbsent(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
"remove(Ljava/lang/Object;Ljava/lang/Object;)Z", "replaceAll(Ljava/util/function/BiFunction;)V",
|
||||
"replace(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
|
||||
"replace(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Z")
|
||||
}
|
||||
|
||||
val BLACK_LIST_CONSTRUCTOR_SIGNATURES: Set<String> =
|
||||
signatures {
|
||||
buildPrimitiveStringConstructorsSet() +
|
||||
inJavaLang("Float", *constructors("D")) +
|
||||
inJavaLang("String", *constructors(
|
||||
"[C", "[CII", "[III", "[BIILjava/lang/String;",
|
||||
"[BIILjava/nio/charset/Charset;",
|
||||
"[BLjava/lang/String;",
|
||||
"[BLjava/nio/charset/Charset;",
|
||||
"[BII", "[B",
|
||||
"Ljava/lang/StringBuffer;",
|
||||
"Ljava/lang/StringBuilder;"
|
||||
))
|
||||
}
|
||||
|
||||
val WHITE_LIST_CONSTRUCTOR_SIGNATURES: Set<String> =
|
||||
signatures {
|
||||
inJavaLang("Throwable", *constructors("Ljava/lang/String;Ljava/lang/Throwable;ZZ"))
|
||||
}
|
||||
|
||||
private fun buildPrimitiveStringConstructorsSet(): Set<String> =
|
||||
signatures {
|
||||
listOf(JvmPrimitiveType.BOOLEAN, JvmPrimitiveType.BYTE, JvmPrimitiveType.DOUBLE, JvmPrimitiveType.FLOAT,
|
||||
JvmPrimitiveType.BYTE, JvmPrimitiveType.INT, JvmPrimitiveType.LONG, JvmPrimitiveType.SHORT
|
||||
).flatMapTo(LinkedHashSet()) {
|
||||
// java/lang/<Wrapper>.<init>(Ljava/lang/String;)V
|
||||
inJavaLang(it.wrapperFqName.shortName().asString(), *constructors("Ljava/lang/String;"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class FallbackBuiltIns private constructor() : KotlinBuiltIns(LockBasedStorageManager()) {
|
||||
init {
|
||||
createBuiltInsModule()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val initializer = BuiltInsInitializer {
|
||||
FallbackBuiltIns()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
val Instance: KotlinBuiltIns
|
||||
get() = initializer.get()
|
||||
}
|
||||
|
||||
override fun getPlatformDependentDeclarationFilter() = PlatformDependentDeclarationFilter.All
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion
|
||||
|
||||
/**
|
||||
* The version of the metadata serialized by the compiler and deserialized by the compiler and reflection.
|
||||
* This version includes the version of the core protobuf messages (descriptors.proto) as well as JVM extensions (jvm_descriptors.proto).
|
||||
*/
|
||||
class JvmMetadataVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
|
||||
// NOTE: 1.1 is incompatible with 1.0 and hence with any other version except 1.1.*
|
||||
override fun isCompatible() =
|
||||
this.major == 1 && this.minor == 1
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val INSTANCE = JvmMetadataVersion(1, 1, 9)
|
||||
|
||||
@JvmField
|
||||
val INVALID_VERSION = JvmMetadataVersion()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.StringTableTypes.Record
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.StringTableTypes.Record.Operation.*
|
||||
import java.util.*
|
||||
|
||||
class JvmNameResolver(
|
||||
private val types: JvmProtoBuf.StringTableTypes,
|
||||
private val strings: Array<String>
|
||||
) : NameResolver {
|
||||
private val localNameIndices = types.localNameList.run { if (isEmpty()) emptySet() else toSet() }
|
||||
|
||||
// Here we expand the 'range' field of the Record message for simplicity to a list of records
|
||||
private val records: List<Record> = ArrayList<Record>().apply {
|
||||
val records = types.recordList
|
||||
this.ensureCapacity(records.size)
|
||||
for (record in records) {
|
||||
repeat(record.range) {
|
||||
this.add(record)
|
||||
}
|
||||
}
|
||||
this.trimToSize()
|
||||
}
|
||||
|
||||
override fun getString(index: Int): String {
|
||||
val record = records[index]
|
||||
|
||||
var string = when {
|
||||
record.hasString() -> record.string
|
||||
record.hasPredefinedIndex() && record.predefinedIndex in PREDEFINED_STRINGS.indices ->
|
||||
PREDEFINED_STRINGS[record.predefinedIndex]
|
||||
else -> strings[index]
|
||||
}
|
||||
|
||||
if (record.substringIndexCount >= 2) {
|
||||
val (begin, end) = record.substringIndexList
|
||||
if (0 <= begin && begin <= end && end <= string.length) {
|
||||
string = string.substring(begin, end)
|
||||
}
|
||||
}
|
||||
|
||||
if (record.replaceCharCount >= 2) {
|
||||
val (from, to) = record.replaceCharList
|
||||
string = string.replace(from.toChar(), to.toChar())
|
||||
}
|
||||
|
||||
when (record.operation ?: NONE) {
|
||||
NONE -> {
|
||||
// Do nothing
|
||||
}
|
||||
INTERNAL_TO_CLASS_ID -> {
|
||||
string = string.replace('$', '.')
|
||||
}
|
||||
DESC_TO_CLASS_ID -> {
|
||||
if (string.length >= 2) {
|
||||
string = string.substring(1, string.length - 1)
|
||||
}
|
||||
string = string.replace('$', '.')
|
||||
}
|
||||
}
|
||||
|
||||
return string
|
||||
}
|
||||
|
||||
override fun getName(index: Int) = Name.guessByFirstCharacter(getString(index))
|
||||
|
||||
override fun getClassId(index: Int): ClassId {
|
||||
val string = getString(index)
|
||||
val lastSlash = string.lastIndexOf('/')
|
||||
val packageName =
|
||||
if (lastSlash < 0) FqName.ROOT
|
||||
else FqName(string.substring(0, lastSlash).replace('/', '.'))
|
||||
val className = FqName(string.substring(lastSlash + 1))
|
||||
return ClassId(packageName, className, index in localNameIndices)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val PREDEFINED_STRINGS = listOf(
|
||||
"kotlin/Any",
|
||||
"kotlin/Nothing",
|
||||
"kotlin/Unit",
|
||||
"kotlin/Throwable",
|
||||
"kotlin/Number",
|
||||
|
||||
"kotlin/Byte", "kotlin/Double", "kotlin/Float", "kotlin/Int",
|
||||
"kotlin/Long", "kotlin/Short", "kotlin/Boolean", "kotlin/Char",
|
||||
|
||||
"kotlin/CharSequence",
|
||||
"kotlin/String",
|
||||
"kotlin/Comparable",
|
||||
"kotlin/Enum",
|
||||
|
||||
"kotlin/Array",
|
||||
"kotlin/ByteArray", "kotlin/DoubleArray", "kotlin/FloatArray", "kotlin/IntArray",
|
||||
"kotlin/LongArray", "kotlin/ShortArray", "kotlin/BooleanArray", "kotlin/CharArray",
|
||||
|
||||
"kotlin/Cloneable",
|
||||
"kotlin/Annotation",
|
||||
|
||||
"kotlin/collections/Iterable", "kotlin/collections/MutableIterable",
|
||||
"kotlin/collections/Collection", "kotlin/collections/MutableCollection",
|
||||
"kotlin/collections/List", "kotlin/collections/MutableList",
|
||||
"kotlin/collections/Set", "kotlin/collections/MutableSet",
|
||||
"kotlin/collections/Map", "kotlin/collections/MutableMap",
|
||||
"kotlin/collections/Map.Entry", "kotlin/collections/MutableMap.MutableEntry",
|
||||
|
||||
"kotlin/collections/Iterator", "kotlin/collections/MutableIterator",
|
||||
"kotlin/collections/ListIterator", "kotlin/collections/MutableListIterator"
|
||||
)
|
||||
|
||||
private val PREDEFINED_STRINGS_MAP = PREDEFINED_STRINGS.withIndex().associateBy({ it.value }, { it.index })
|
||||
|
||||
fun getPredefinedStringIndex(string: String): Int? = PREDEFINED_STRINGS_MAP[string]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.SourceFile
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||
|
||||
class JvmPackagePartSource(
|
||||
val className: JvmClassName,
|
||||
val facadeClassName: JvmClassName?,
|
||||
override val incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>? = null,
|
||||
override val isPreReleaseInvisible: Boolean = false,
|
||||
val knownJvmBinaryClass: KotlinJvmBinaryClass? = null
|
||||
) : DeserializedContainerSource {
|
||||
constructor(
|
||||
kotlinClass: KotlinJvmBinaryClass,
|
||||
incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>? = null,
|
||||
isPreReleaseInvisible: Boolean = false
|
||||
) : this(
|
||||
JvmClassName.byClassId(kotlinClass.classId),
|
||||
kotlinClass.classHeader.multifileClassName?.let {
|
||||
if (it.isNotEmpty()) JvmClassName.byInternalName(it) else null
|
||||
},
|
||||
incompatibility,
|
||||
isPreReleaseInvisible,
|
||||
kotlinClass
|
||||
)
|
||||
|
||||
override val presentableString: String
|
||||
get() = "Class '${classId.asSingleFqName().asString()}'"
|
||||
|
||||
val simpleName: Name get() = Name.identifier(className.internalName.substringAfterLast('/'))
|
||||
|
||||
val classId: ClassId get() = ClassId(className.packageFqName, simpleName)
|
||||
|
||||
override fun toString() = "${this::class.java.simpleName}: $className"
|
||||
|
||||
override fun getContainingFile(): SourceFile = SourceFile.NO_SOURCE_FILE
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.serialization.deserialization.KotlinMetadataFinder
|
||||
|
||||
interface KotlinClassFinder : KotlinMetadataFinder {
|
||||
fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass?
|
||||
|
||||
fun findKotlinClass(javaClass: JavaClass): KotlinJvmBinaryClass?
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
interface KotlinJvmBinaryClass {
|
||||
val classId: ClassId
|
||||
|
||||
/**
|
||||
* @return path to the class file (to be reported to the user upon error)
|
||||
*/
|
||||
val location: String
|
||||
|
||||
fun loadClassAnnotations(visitor: AnnotationVisitor, cachedContents: ByteArray?)
|
||||
|
||||
fun visitMembers(visitor: MemberVisitor, cachedContents: ByteArray?)
|
||||
|
||||
val classHeader: KotlinClassHeader
|
||||
|
||||
interface MemberVisitor {
|
||||
// TODO: abstract signatures for methods and fields instead of ASM 'desc' strings?
|
||||
|
||||
fun visitMethod(name: Name, desc: String): MethodAnnotationVisitor?
|
||||
|
||||
fun visitField(name: Name, desc: String, initializer: Any?): AnnotationVisitor?
|
||||
}
|
||||
|
||||
interface AnnotationVisitor {
|
||||
fun visitAnnotation(classId: ClassId, source: SourceElement): AnnotationArgumentVisitor?
|
||||
|
||||
fun visitEnd()
|
||||
}
|
||||
|
||||
interface MethodAnnotationVisitor : AnnotationVisitor {
|
||||
fun visitParameterAnnotation(index: Int, classId: ClassId, source: SourceElement): AnnotationArgumentVisitor?
|
||||
}
|
||||
|
||||
interface AnnotationArgumentVisitor {
|
||||
// TODO: class literals
|
||||
fun visit(name: Name?, value: Any?)
|
||||
|
||||
fun visitEnum(name: Name, enumClassId: ClassId, enumEntryName: Name)
|
||||
|
||||
fun visitAnnotation(name: Name, classId: ClassId): AnnotationArgumentVisitor?
|
||||
|
||||
fun visitArray(name: Name): AnnotationArrayArgumentVisitor?
|
||||
|
||||
fun visitEnd()
|
||||
}
|
||||
|
||||
interface AnnotationArrayArgumentVisitor {
|
||||
fun visit(value: Any?)
|
||||
|
||||
fun visitEnum(enumClassId: ClassId, enumEntryName: Name)
|
||||
|
||||
fun visitEnd()
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.descriptors.SourceFile
|
||||
import org.jetbrains.kotlin.load.java.descriptors.getImplClassNameForDeserialized
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageFragment
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor
|
||||
|
||||
class KotlinJvmBinaryPackageSourceElement(
|
||||
private val packageFragment: LazyJavaPackageFragment
|
||||
) : SourceElement {
|
||||
override fun toString() = "$packageFragment: ${packageFragment.binaryClasses.keys}"
|
||||
|
||||
override fun getContainingFile(): SourceFile = SourceFile.NO_SOURCE_FILE
|
||||
|
||||
fun getRepresentativeBinaryClass(): KotlinJvmBinaryClass {
|
||||
return packageFragment.binaryClasses.values.first()
|
||||
}
|
||||
|
||||
fun getContainingBinaryClass(descriptor: DeserializedMemberDescriptor): KotlinJvmBinaryClass? {
|
||||
val name = descriptor.getImplClassNameForDeserialized() ?: return null
|
||||
return packageFragment.binaryClasses[name.internalName]
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.SourceFile
|
||||
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||
|
||||
class KotlinJvmBinarySourceElement(
|
||||
val binaryClass: KotlinJvmBinaryClass,
|
||||
override val incompatibility: IncompatibleVersionErrorData<JvmMetadataVersion>? = null,
|
||||
override val isPreReleaseInvisible: Boolean = false
|
||||
) : DeserializedContainerSource {
|
||||
override val presentableString: String
|
||||
get() = "Class '${binaryClass.classId.asSingleFqName().asString()}'"
|
||||
|
||||
override fun getContainingFile(): SourceFile = SourceFile.NO_SOURCE_FILE
|
||||
|
||||
override fun toString() = "${this::class.java.simpleName}: $binaryClass"
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
|
||||
// The purpose of this class is to hold a unique signature of either a method or a field, so that annotations on a member can be put
|
||||
// into a map indexed by these signatures
|
||||
data class MemberSignature private constructor(internal val signature: String) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun fromMethod(nameResolver: NameResolver, signature: JvmProtoBuf.JvmMethodSignature): MemberSignature {
|
||||
return fromMethodNameAndDesc(nameResolver.getString(signature.name), nameResolver.getString(signature.desc))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun fromMethodNameAndDesc(name: String, desc: String): MemberSignature {
|
||||
return MemberSignature(name + desc)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun fromMethodNameAndDesc(namePlusDesc: String): MemberSignature {
|
||||
return MemberSignature(namePlusDesc)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun fromFieldNameAndDesc(name: String, desc: String): MemberSignature {
|
||||
return MemberSignature(name + "#" + desc)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun fromMethodSignatureAndParameterIndex(signature: MemberSignature, index: Int): MemberSignature {
|
||||
return MemberSignature(signature.signature + "@" + index)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmPackageTable
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.DataInputStream
|
||||
import java.io.IOException
|
||||
|
||||
class ModuleMapping private constructor(val packageFqName2Parts: Map<String, PackageParts>, private val debugName: String) {
|
||||
fun findPackageParts(packageFqName: String): PackageParts? {
|
||||
return packageFqName2Parts[packageFqName]
|
||||
}
|
||||
|
||||
override fun toString() = debugName
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val MAPPING_FILE_EXT: String = "kotlin_module"
|
||||
|
||||
@JvmField
|
||||
val EMPTY: ModuleMapping = ModuleMapping(emptyMap(), "EMPTY")
|
||||
|
||||
@JvmField
|
||||
val CORRUPTED: ModuleMapping = ModuleMapping(emptyMap(), "CORRUPTED")
|
||||
|
||||
fun create(
|
||||
bytes: ByteArray?,
|
||||
debugName: String,
|
||||
configuration: DeserializationConfiguration
|
||||
): ModuleMapping {
|
||||
if (bytes == null) {
|
||||
return EMPTY
|
||||
}
|
||||
|
||||
val stream = DataInputStream(ByteArrayInputStream(bytes))
|
||||
|
||||
val versionNumber = try {
|
||||
IntArray(stream.readInt()) { stream.readInt() }
|
||||
}
|
||||
catch (e: IOException) {
|
||||
return CORRUPTED
|
||||
}
|
||||
|
||||
val version = JvmMetadataVersion(*versionNumber)
|
||||
|
||||
if (configuration.skipMetadataVersionCheck || version.isCompatible()) {
|
||||
val table = JvmPackageTable.PackageTable.parseFrom(stream) ?: return EMPTY
|
||||
val result = linkedMapOf<String, PackageParts>()
|
||||
|
||||
for (proto in table.packagePartsList) {
|
||||
val packageFqName = proto.packageFqName
|
||||
val packageParts = result.getOrPut(packageFqName) { PackageParts(packageFqName) }
|
||||
|
||||
for ((index, partShortName) in proto.shortClassNameList.withIndex()) {
|
||||
val multifileFacadeId = proto.multifileFacadeShortNameIdList.getOrNull(index)?.minus(1)
|
||||
val facadeShortName = multifileFacadeId?.let(proto.multifileFacadeShortNameList::getOrNull)
|
||||
val facadeInternalName = facadeShortName?.let { internalNameOf(packageFqName, it) }
|
||||
packageParts.addPart(internalNameOf(packageFqName, partShortName), facadeInternalName)
|
||||
}
|
||||
|
||||
if (configuration.isJvmPackageNameSupported) {
|
||||
for ((index, partShortName) in proto.classWithJvmPackageNameShortNameList.withIndex()) {
|
||||
val packageId = proto.classWithJvmPackageNamePackageIdList.getOrNull(index)
|
||||
?: proto.classWithJvmPackageNamePackageIdList.lastOrNull()
|
||||
?: continue
|
||||
val jvmPackageName = table.jvmPackageNameList.getOrNull(packageId) ?: continue
|
||||
packageParts.addPart(internalNameOf(jvmPackageName, partShortName), null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (proto in table.metadataPartsList) {
|
||||
val packageParts = result.getOrPut(proto.packageFqName) { PackageParts(proto.packageFqName) }
|
||||
proto.shortClassNameList.forEach(packageParts::addMetadataPart)
|
||||
}
|
||||
|
||||
return ModuleMapping(result, debugName)
|
||||
}
|
||||
else {
|
||||
// TODO: consider reporting "incompatible ABI version" error for package parts
|
||||
}
|
||||
|
||||
return EMPTY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun internalNameOf(packageFqName: String, className: String): String =
|
||||
JvmClassName.byFqNameWithoutInnerClasses(FqName(packageFqName).child(Name.identifier(className))).internalName
|
||||
|
||||
class PackageParts(val packageFqName: String) {
|
||||
// JVM internal name of package part -> JVM internal name of the corresponding multifile facade (or null, if it's not a multifile part)
|
||||
private val packageParts = linkedMapOf<String, String?>()
|
||||
val parts: Set<String> get() = packageParts.keys
|
||||
|
||||
// Short names of .kotlin_metadata package parts
|
||||
val metadataParts: Set<String> = linkedSetOf()
|
||||
|
||||
fun addPart(partInternalName: String, facadeInternalName: String?) {
|
||||
packageParts[partInternalName] = facadeInternalName
|
||||
}
|
||||
|
||||
fun removePart(internalName: String) {
|
||||
packageParts.remove(internalName)
|
||||
}
|
||||
|
||||
fun addMetadataPart(shortName: String) {
|
||||
(metadataParts as MutableSet /* see KT-14663 */).add(shortName)
|
||||
}
|
||||
|
||||
fun addTo(builder: JvmPackageTable.PackageTable.Builder) {
|
||||
if (parts.isNotEmpty()) {
|
||||
builder.addPackageParts(JvmPackageTable.PackageParts.newBuilder().apply {
|
||||
packageFqName = this@PackageParts.packageFqName
|
||||
|
||||
val packageInternalName = packageFqName.replace('.', '/')
|
||||
val (partsWithinPackage, partsOutsidePackage) = parts.partition { partInternalName ->
|
||||
partInternalName.packageName == packageInternalName
|
||||
}
|
||||
|
||||
writePartsWithinPackage(partsWithinPackage)
|
||||
|
||||
writePartsOutsidePackage(partsOutsidePackage, builder)
|
||||
})
|
||||
}
|
||||
|
||||
if (metadataParts.isNotEmpty()) {
|
||||
builder.addMetadataParts(JvmPackageTable.PackageParts.newBuilder().apply {
|
||||
packageFqName = this@PackageParts.packageFqName
|
||||
addAllShortClassName(metadataParts.sorted())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun JvmPackageTable.PackageParts.Builder.writePartsWithinPackage(parts: List<String>) {
|
||||
val facadeNameToId = mutableMapOf<String, Int>()
|
||||
for ((facadeInternalName, partInternalNames) in parts.groupBy { getMultifileFacadeName(it) }.toSortedMap(nullsLast())) {
|
||||
for (partInternalName in partInternalNames.sorted()) {
|
||||
addShortClassName(partInternalName.className)
|
||||
if (facadeInternalName != null) {
|
||||
addMultifileFacadeShortNameId(1 + facadeNameToId.getOrPut(facadeInternalName.className) { facadeNameToId.size })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ((facadeId, facadeName) in facadeNameToId.values.zip(facadeNameToId.keys).sortedBy(Pair<Int, String>::first)) {
|
||||
assert(facadeId == multifileFacadeShortNameCount) { "Multifile facades are loaded incorrectly: $facadeNameToId" }
|
||||
addMultifileFacadeShortName(facadeName)
|
||||
}
|
||||
}
|
||||
|
||||
// Writes information about package parts which have a different JVM package from the Kotlin package (with the help of @JvmPackageName)
|
||||
private fun JvmPackageTable.PackageParts.Builder.writePartsOutsidePackage(
|
||||
parts: List<String>,
|
||||
packageTableBuilder: JvmPackageTable.PackageTable.Builder
|
||||
) {
|
||||
val packageIds = mutableListOf<Int>()
|
||||
for ((packageInternalName, partsInPackage) in parts.groupBy { it.packageName }.toSortedMap()) {
|
||||
val packageFqName = packageInternalName.replace('/', '.')
|
||||
if (packageFqName !in packageTableBuilder.jvmPackageNameList) {
|
||||
packageTableBuilder.addJvmPackageName(packageFqName)
|
||||
}
|
||||
val packageId = packageTableBuilder.jvmPackageNameList.indexOf(packageFqName)
|
||||
for (part in partsInPackage.map { it.className }.sorted()) {
|
||||
addClassWithJvmPackageNameShortName(part)
|
||||
packageIds.add(packageId)
|
||||
}
|
||||
}
|
||||
|
||||
// See PackageParts#class_with_jvm_package_name_package_id in jvm_package_table.proto for description of this optimization
|
||||
while (packageIds.size > 1 && packageIds[packageIds.size - 1] == packageIds[packageIds.size - 2]) {
|
||||
packageIds.removeAt(packageIds.size - 1)
|
||||
}
|
||||
|
||||
addAllClassWithJvmPackageNamePackageId(packageIds)
|
||||
}
|
||||
|
||||
private val String.packageName: String get() = substringBeforeLast('/', "")
|
||||
private val String.className: String get() = substringAfterLast('/')
|
||||
|
||||
fun getMultifileFacadeName(partInternalName: String): String? = packageParts[partInternalName]
|
||||
|
||||
operator fun plusAssign(other: PackageParts) {
|
||||
for ((partInternalName, facadeInternalName) in other.packageParts) {
|
||||
addPart(partInternalName, facadeInternalName)
|
||||
}
|
||||
other.metadataParts.forEach(this::addMetadataPart)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is PackageParts &&
|
||||
other.packageFqName == packageFqName && other.packageParts == packageParts && other.metadataParts == metadataParts
|
||||
|
||||
override fun hashCode() =
|
||||
(packageFqName.hashCode() * 31 + packageParts.hashCode()) * 31 + metadataParts.hashCode()
|
||||
|
||||
override fun toString() =
|
||||
(parts + metadataParts).toString()
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
class TypeMappingMode private constructor(
|
||||
val needPrimitiveBoxing: Boolean = true,
|
||||
val isForAnnotationParameter: Boolean = false,
|
||||
// Here DeclarationSiteWildcards means wildcard generated because of declaration-site variance
|
||||
val skipDeclarationSiteWildcards: Boolean = false,
|
||||
val skipDeclarationSiteWildcardsIfPossible: Boolean = false,
|
||||
private val genericArgumentMode: TypeMappingMode? = null,
|
||||
val kotlinCollectionsToJavaCollections: Boolean = true,
|
||||
private val genericContravariantArgumentMode: TypeMappingMode? = genericArgumentMode,
|
||||
private val genericInvariantArgumentMode: TypeMappingMode? = genericArgumentMode
|
||||
) {
|
||||
companion object {
|
||||
/**
|
||||
* kotlin.Int is mapped to Ljava/lang/Integer;
|
||||
*/
|
||||
@JvmField
|
||||
val GENERIC_ARGUMENT = TypeMappingMode()
|
||||
|
||||
/**
|
||||
* kotlin.Int is mapped to I
|
||||
*/
|
||||
@JvmField
|
||||
val DEFAULT = TypeMappingMode(genericArgumentMode = GENERIC_ARGUMENT, needPrimitiveBoxing = false)
|
||||
|
||||
/**
|
||||
* kotlin.Int is mapped to Ljava/lang/Integer;
|
||||
* No projections allowed in immediate arguments
|
||||
*/
|
||||
@JvmField
|
||||
val SUPER_TYPE = TypeMappingMode(skipDeclarationSiteWildcards = true, genericArgumentMode = GENERIC_ARGUMENT)
|
||||
|
||||
@JvmField
|
||||
val SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS = TypeMappingMode(
|
||||
skipDeclarationSiteWildcards = true,
|
||||
genericArgumentMode = GENERIC_ARGUMENT,
|
||||
kotlinCollectionsToJavaCollections = false
|
||||
)
|
||||
|
||||
/**
|
||||
* kotlin.reflect.KClass mapped to java.lang.Class
|
||||
* Other types mapped as DEFAULT
|
||||
*/
|
||||
@JvmField
|
||||
val VALUE_FOR_ANNOTATION = TypeMappingMode(
|
||||
isForAnnotationParameter = true,
|
||||
needPrimitiveBoxing = false,
|
||||
genericArgumentMode = TypeMappingMode(isForAnnotationParameter = true, genericArgumentMode = GENERIC_ARGUMENT))
|
||||
|
||||
|
||||
@JvmStatic
|
||||
fun getModeForReturnTypeNoGeneric(
|
||||
isAnnotationMethod: Boolean
|
||||
) = if (isAnnotationMethod) VALUE_FOR_ANNOTATION else DEFAULT
|
||||
|
||||
@JvmStatic
|
||||
fun getOptimalModeForValueParameter(
|
||||
type: KotlinType
|
||||
) = getOptimalModeForSignaturePart(type, isForAnnotationParameter = false, canBeUsedInSupertypePosition = true)
|
||||
|
||||
@JvmStatic
|
||||
fun getOptimalModeForReturnType(
|
||||
type: KotlinType,
|
||||
isAnnotationMethod: Boolean
|
||||
) = getOptimalModeForSignaturePart(type, isForAnnotationParameter = isAnnotationMethod, canBeUsedInSupertypePosition = false)
|
||||
|
||||
private fun getOptimalModeForSignaturePart(
|
||||
type: KotlinType,
|
||||
isForAnnotationParameter: Boolean,
|
||||
canBeUsedInSupertypePosition: Boolean
|
||||
): TypeMappingMode {
|
||||
if (type.arguments.isEmpty()) return DEFAULT
|
||||
|
||||
val contravariantArgumentMode =
|
||||
if (!canBeUsedInSupertypePosition)
|
||||
TypeMappingMode(
|
||||
isForAnnotationParameter = isForAnnotationParameter,
|
||||
skipDeclarationSiteWildcards = false,
|
||||
skipDeclarationSiteWildcardsIfPossible = true)
|
||||
else
|
||||
null
|
||||
|
||||
val invariantArgumentMode =
|
||||
if (canBeUsedInSupertypePosition)
|
||||
getOptimalModeForSignaturePart(type, isForAnnotationParameter, canBeUsedInSupertypePosition = false)
|
||||
else
|
||||
null
|
||||
|
||||
return TypeMappingMode(
|
||||
isForAnnotationParameter = isForAnnotationParameter,
|
||||
skipDeclarationSiteWildcards = !canBeUsedInSupertypePosition,
|
||||
skipDeclarationSiteWildcardsIfPossible = true,
|
||||
genericContravariantArgumentMode = contravariantArgumentMode,
|
||||
genericInvariantArgumentMode = invariantArgumentMode)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun createWithConstantDeclarationSiteWildcardsMode(
|
||||
skipDeclarationSiteWildcards: Boolean,
|
||||
isForAnnotationParameter: Boolean,
|
||||
fallbackMode: TypeMappingMode? = null
|
||||
) = TypeMappingMode(
|
||||
isForAnnotationParameter = isForAnnotationParameter,
|
||||
skipDeclarationSiteWildcards = skipDeclarationSiteWildcards,
|
||||
genericArgumentMode = fallbackMode)
|
||||
}
|
||||
|
||||
fun toGenericArgumentMode(effectiveVariance: Variance): TypeMappingMode =
|
||||
when (effectiveVariance) {
|
||||
Variance.IN_VARIANCE -> genericContravariantArgumentMode ?: this
|
||||
Variance.INVARIANT -> genericInvariantArgumentMode ?: this
|
||||
else -> genericArgumentMode ?: this
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
|
||||
import org.jetbrains.kotlin.descriptors.annotations.BuiltInAnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.composeAnnotations
|
||||
import org.jetbrains.kotlin.types.*
|
||||
|
||||
internal class UnsafeVarianceTypeSubstitution(builtIns: KotlinBuiltIns) : TypeSubstitution() {
|
||||
private val unsafeVarianceAnnotations = AnnotationsImpl(listOf(
|
||||
BuiltInAnnotationDescriptor(builtIns, KotlinBuiltIns.FQ_NAMES.unsafeVariance, emptyMap())
|
||||
))
|
||||
|
||||
override fun get(key: KotlinType) = null
|
||||
|
||||
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance): KotlinType {
|
||||
val unsafeVariancePaths = mutableListOf<List<Int>>()
|
||||
IndexedTypeHolder(topLevelType).checkTypePosition(
|
||||
position,
|
||||
{ _, indexedTypeHolder, _ ->
|
||||
unsafeVariancePaths.add(indexedTypeHolder.argumentIndices)
|
||||
},
|
||||
customVariance = { null })
|
||||
|
||||
return topLevelType.unwrap().annotatePartsWithUnsafeVariance(unsafeVariancePaths)
|
||||
}
|
||||
private fun UnwrappedType.annotatePartsWithUnsafeVariance(unsafeVariancePaths: Collection<List<Int>>): UnwrappedType {
|
||||
if (unsafeVariancePaths.isEmpty()) return this
|
||||
return when (this) {
|
||||
is FlexibleType ->
|
||||
KotlinTypeFactory.flexibleType(
|
||||
lowerBound.annotatePartsWithUnsafeVariance(subPathsWithIndex(unsafeVariancePaths, 0)),
|
||||
upperBound.annotatePartsWithUnsafeVariance(subPathsWithIndex(unsafeVariancePaths, 1))
|
||||
).inheritEnhancement(this)
|
||||
is SimpleType -> annotatePartsWithUnsafeVariance(unsafeVariancePaths)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SimpleType.annotatePartsWithUnsafeVariance(unsafeVariancePaths: Collection<List<Int>>): SimpleType {
|
||||
if (unsafeVariancePaths.isEmpty()) return this
|
||||
|
||||
// if root is unsafe
|
||||
if (emptyList<Int>() in unsafeVariancePaths) {
|
||||
return replaceAnnotations(composeAnnotations(annotations, unsafeVarianceAnnotations))
|
||||
}
|
||||
|
||||
return replace(newArguments = arguments.withIndex().map {
|
||||
val (index, argument) = it
|
||||
if (argument.isStarProjection) return@map argument
|
||||
TypeProjectionImpl(
|
||||
argument.projectionKind,
|
||||
argument.type.unwrap().annotatePartsWithUnsafeVariance(subPathsWithIndex(unsafeVariancePaths, index)))
|
||||
})
|
||||
}
|
||||
|
||||
private fun subPathsWithIndex(paths: Collection<List<Int>>, index: Int) = paths.filter { it[0] == index }.map { it.subList(1, it.size) }
|
||||
|
||||
private class IndexedTypeHolder(
|
||||
override val type: KotlinType,
|
||||
val argumentIndices: List<Int> = emptyList()
|
||||
) : TypeHolder<IndexedTypeHolder> {
|
||||
override val flexibleBounds: Pair<IndexedTypeHolder, IndexedTypeHolder>? get() =
|
||||
if (type.isFlexible())
|
||||
Pair(
|
||||
IndexedTypeHolder(type.lowerIfFlexible(), argumentIndices + 0),
|
||||
IndexedTypeHolder(type.upperIfFlexible(), argumentIndices + 1))
|
||||
else null
|
||||
|
||||
override val arguments: List<TypeHolderArgument<IndexedTypeHolder>>
|
||||
get() = type.arguments.withIndex().map { projectionWithIndex ->
|
||||
|
||||
val (index, projection) = projectionWithIndex
|
||||
object : TypeHolderArgument<IndexedTypeHolder> {
|
||||
override val projection: TypeProjection
|
||||
get() = projection
|
||||
override val typeParameter: TypeParameterDescriptor?
|
||||
get() = type.constructor.parameters[index]
|
||||
override val holder: IndexedTypeHolder
|
||||
get() = IndexedTypeHolder(projection.type, argumentIndices + index)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.kotlin.header
|
||||
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader.MultifileClassKind.DELEGATING
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader.MultifileClassKind.INHERITING
|
||||
|
||||
class KotlinClassHeader(
|
||||
val kind: KotlinClassHeader.Kind,
|
||||
val metadataVersion: JvmMetadataVersion,
|
||||
val bytecodeVersion: JvmBytecodeBinaryVersion,
|
||||
val data: Array<String>?,
|
||||
val incompatibleData: Array<String>?,
|
||||
val strings: Array<String>?,
|
||||
val extraString: String?,
|
||||
val extraInt: Int,
|
||||
val packageName: String?
|
||||
) {
|
||||
// See kotlin.Metadata
|
||||
enum class Kind(val id: Int) {
|
||||
UNKNOWN(0),
|
||||
CLASS(1),
|
||||
FILE_FACADE(2),
|
||||
SYNTHETIC_CLASS(3),
|
||||
MULTIFILE_CLASS(4),
|
||||
MULTIFILE_CLASS_PART(5);
|
||||
|
||||
companion object {
|
||||
private val entryById = values().associateBy(Kind::id)
|
||||
|
||||
@JvmStatic
|
||||
fun getById(id: Int) = entryById[id] ?: UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
enum class MultifileClassKind {
|
||||
DELEGATING,
|
||||
INHERITING;
|
||||
}
|
||||
|
||||
val multifileClassName: String?
|
||||
get() = extraString.takeIf { kind == Kind.MULTIFILE_CLASS_PART }
|
||||
|
||||
val multifilePartNames: List<String>
|
||||
get() = data.takeIf { kind == Kind.MULTIFILE_CLASS }?.asList().orEmpty()
|
||||
|
||||
// TODO: use in incremental compilation
|
||||
val multifileClassKind: MultifileClassKind?
|
||||
get() = if (kind == Kind.MULTIFILE_CLASS || kind == Kind.MULTIFILE_CLASS_PART) {
|
||||
if ((extraInt and JvmAnnotationNames.METADATA_MULTIFILE_PARTS_INHERIT_FLAG) != 0)
|
||||
INHERITING
|
||||
else
|
||||
DELEGATING
|
||||
}
|
||||
else
|
||||
null
|
||||
|
||||
val isPreRelease: Boolean
|
||||
get() = (extraInt and JvmAnnotationNames.METADATA_PRE_RELEASE_FLAG) != 0
|
||||
|
||||
val isScript: Boolean
|
||||
get() = (extraInt and JvmAnnotationNames.METADATA_SCRIPT_FLAG) != 0
|
||||
|
||||
override fun toString() = "$kind version=$metadataVersion"
|
||||
}
|
||||
+312
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* 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.kotlin.header;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement;
|
||||
import org.jetbrains.kotlin.load.java.JvmBytecodeBinaryVersion;
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.*;
|
||||
import static org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass.*;
|
||||
import static org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader.Kind.*;
|
||||
|
||||
public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor {
|
||||
private static final boolean IGNORE_OLD_METADATA = "true".equals(System.getProperty("kotlin.ignore.old.metadata"));
|
||||
|
||||
private static final Map<ClassId, KotlinClassHeader.Kind> HEADER_KINDS = new HashMap<ClassId, KotlinClassHeader.Kind>();
|
||||
|
||||
static {
|
||||
// TODO: delete this at some point
|
||||
HEADER_KINDS.put(ClassId.topLevel(new FqName("kotlin.jvm.internal.KotlinClass")), CLASS);
|
||||
HEADER_KINDS.put(ClassId.topLevel(new FqName("kotlin.jvm.internal.KotlinFileFacade")), FILE_FACADE);
|
||||
HEADER_KINDS.put(ClassId.topLevel(new FqName("kotlin.jvm.internal.KotlinMultifileClass")), MULTIFILE_CLASS);
|
||||
HEADER_KINDS.put(ClassId.topLevel(new FqName("kotlin.jvm.internal.KotlinMultifileClassPart")), MULTIFILE_CLASS_PART);
|
||||
HEADER_KINDS.put(ClassId.topLevel(new FqName("kotlin.jvm.internal.KotlinSyntheticClass")), SYNTHETIC_CLASS);
|
||||
}
|
||||
|
||||
private JvmMetadataVersion metadataVersion = null;
|
||||
private JvmBytecodeBinaryVersion bytecodeVersion = null;
|
||||
private String extraString = null;
|
||||
private int extraInt = 0;
|
||||
private String packageName = null;
|
||||
private String[] data = null;
|
||||
private String[] strings = null;
|
||||
private String[] incompatibleData = null;
|
||||
private KotlinClassHeader.Kind headerKind = null;
|
||||
|
||||
@Nullable
|
||||
public KotlinClassHeader createHeader() {
|
||||
if (headerKind == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!metadataVersion.isCompatible()) {
|
||||
incompatibleData = data;
|
||||
}
|
||||
|
||||
if (metadataVersion == null || !metadataVersion.isCompatible()) {
|
||||
data = null;
|
||||
}
|
||||
else if (shouldHaveData() && data == null) {
|
||||
// This means that the annotation is found and its ABI version is compatible, but there's no "data" string array in it.
|
||||
// We tell the outside world that there's really no annotation at all
|
||||
return null;
|
||||
}
|
||||
|
||||
return new KotlinClassHeader(
|
||||
headerKind,
|
||||
metadataVersion != null ? metadataVersion : JvmMetadataVersion.INVALID_VERSION,
|
||||
bytecodeVersion != null ? bytecodeVersion : JvmBytecodeBinaryVersion.INVALID_VERSION,
|
||||
data,
|
||||
incompatibleData,
|
||||
strings,
|
||||
extraString,
|
||||
extraInt,
|
||||
packageName
|
||||
);
|
||||
}
|
||||
|
||||
private boolean shouldHaveData() {
|
||||
return headerKind == CLASS ||
|
||||
headerKind == FILE_FACADE ||
|
||||
headerKind == MULTIFILE_CLASS_PART;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public AnnotationArgumentVisitor visitAnnotation(@NotNull ClassId classId, @NotNull SourceElement source) {
|
||||
FqName fqName = classId.asSingleFqName();
|
||||
if (fqName.equals(METADATA_FQ_NAME)) {
|
||||
return new KotlinMetadataArgumentVisitor();
|
||||
}
|
||||
|
||||
if (IGNORE_OLD_METADATA) return null;
|
||||
|
||||
if (headerKind != null) {
|
||||
// Ignore all Kotlin annotations except the first found
|
||||
return null;
|
||||
}
|
||||
|
||||
KotlinClassHeader.Kind newKind = HEADER_KINDS.get(classId);
|
||||
if (newKind != null) {
|
||||
headerKind = newKind;
|
||||
return new OldDeprecatedAnnotationArgumentVisitor();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
}
|
||||
|
||||
private class KotlinMetadataArgumentVisitor implements AnnotationArgumentVisitor {
|
||||
@Override
|
||||
public void visit(@Nullable Name name, @Nullable Object value) {
|
||||
if (name == null) return;
|
||||
|
||||
String string = name.asString();
|
||||
if (KIND_FIELD_NAME.equals(string)) {
|
||||
if (value instanceof Integer) {
|
||||
headerKind = KotlinClassHeader.Kind.getById((Integer) value);
|
||||
}
|
||||
}
|
||||
else if (METADATA_VERSION_FIELD_NAME.equals(string)) {
|
||||
if (value instanceof int[]) {
|
||||
metadataVersion = new JvmMetadataVersion((int[]) value);
|
||||
}
|
||||
}
|
||||
else if (BYTECODE_VERSION_FIELD_NAME.equals(string)) {
|
||||
if (value instanceof int[]) {
|
||||
bytecodeVersion = new JvmBytecodeBinaryVersion((int[]) value);
|
||||
}
|
||||
}
|
||||
else if (METADATA_EXTRA_STRING_FIELD_NAME.equals(string)) {
|
||||
if (value instanceof String) {
|
||||
extraString = (String) value;
|
||||
}
|
||||
}
|
||||
else if (METADATA_EXTRA_INT_FIELD_NAME.equals(string)) {
|
||||
if (value instanceof Integer) {
|
||||
extraInt = (Integer) value;
|
||||
}
|
||||
}
|
||||
else if (METADATA_PACKAGE_NAME_FIELD_NAME.equals(string)) {
|
||||
if (value instanceof String) {
|
||||
packageName = (String) value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public AnnotationArrayArgumentVisitor visitArray(@NotNull Name name) {
|
||||
String string = name.asString();
|
||||
if (METADATA_DATA_FIELD_NAME.equals(string)) {
|
||||
return dataArrayVisitor();
|
||||
}
|
||||
else if (METADATA_STRINGS_FIELD_NAME.equals(string)) {
|
||||
return stringsArrayVisitor();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AnnotationArrayArgumentVisitor dataArrayVisitor() {
|
||||
return new CollectStringArrayAnnotationVisitor() {
|
||||
@Override
|
||||
protected void visitEnd(@NotNull String[] result) {
|
||||
data = result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AnnotationArrayArgumentVisitor stringsArrayVisitor() {
|
||||
return new CollectStringArrayAnnotationVisitor() {
|
||||
@Override
|
||||
protected void visitEnd(@NotNull String[] result) {
|
||||
strings = result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(@NotNull Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public AnnotationArgumentVisitor visitAnnotation(@NotNull Name name, @NotNull ClassId classId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
}
|
||||
}
|
||||
|
||||
private class OldDeprecatedAnnotationArgumentVisitor implements AnnotationArgumentVisitor {
|
||||
@Override
|
||||
public void visit(@Nullable Name name, @Nullable Object value) {
|
||||
if (name == null) return;
|
||||
|
||||
String string = name.asString();
|
||||
if ("version".equals(string)) {
|
||||
if (value instanceof int[]) {
|
||||
metadataVersion = new JvmMetadataVersion((int[]) value);
|
||||
|
||||
// If there's no bytecode binary version in the class file, we assume it to be equal to the metadata version
|
||||
if (bytecodeVersion == null) {
|
||||
bytecodeVersion = new JvmBytecodeBinaryVersion((int[]) value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ("multifileClassName".equals(string)) {
|
||||
extraString = value instanceof String ? (String) value : null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public AnnotationArrayArgumentVisitor visitArray(@NotNull Name name) {
|
||||
String string = name.asString();
|
||||
if ("data".equals(string) || "filePartClassNames".equals(string)) {
|
||||
return dataArrayVisitor();
|
||||
}
|
||||
else if ("strings".equals(string)) {
|
||||
return stringsArrayVisitor();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AnnotationArrayArgumentVisitor dataArrayVisitor() {
|
||||
return new CollectStringArrayAnnotationVisitor() {
|
||||
@Override
|
||||
protected void visitEnd(@NotNull String[] data) {
|
||||
ReadKotlinClassHeaderAnnotationVisitor.this.data = data;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private AnnotationArrayArgumentVisitor stringsArrayVisitor() {
|
||||
return new CollectStringArrayAnnotationVisitor() {
|
||||
@Override
|
||||
protected void visitEnd(@NotNull String[] data) {
|
||||
strings = data;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(@NotNull Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public AnnotationArgumentVisitor visitAnnotation(@NotNull Name name, @NotNull ClassId classId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class CollectStringArrayAnnotationVisitor implements AnnotationArrayArgumentVisitor {
|
||||
private final List<String> strings;
|
||||
|
||||
public CollectStringArrayAnnotationVisitor() {
|
||||
this.strings = new ArrayList<String>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(@Nullable Object value) {
|
||||
if (value instanceof String) {
|
||||
strings.add((String) value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(@NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
//noinspection SSBasedInspection
|
||||
visitEnd(strings.toArray(new String[strings.size()]));
|
||||
}
|
||||
|
||||
protected abstract void visitEnd(@NotNull String[] data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import java.util.*
|
||||
|
||||
inline fun <T> signatures(block: SignatureBuildingComponents.() -> T) = with(SignatureBuildingComponents, block)
|
||||
|
||||
object SignatureBuildingComponents {
|
||||
fun javaLang(name: String) = "java/lang/$name"
|
||||
fun javaUtil(name: String) = "java/util/$name"
|
||||
fun javaFunction(name: String) = "java/util/function/$name"
|
||||
|
||||
fun constructors(vararg signatures: String) = signatures.map { "<init>($it)V" }.toTypedArray()
|
||||
|
||||
fun inJavaLang(name: String, vararg signatures: String) = inClass(javaLang(name), *signatures)
|
||||
fun inJavaUtil(name: String, vararg signatures: String) = inClass(javaUtil(name), *signatures)
|
||||
|
||||
fun inClass(internalName: String, vararg signatures: String) = signatures.mapTo(LinkedHashSet()) { internalName + "." + it }
|
||||
|
||||
fun signature(classDescriptor: ClassDescriptor, jvmDescriptor: String) = signature(classDescriptor.internalName, jvmDescriptor)
|
||||
fun signature(classId: ClassId, jvmDescriptor: String) = signature(classId.internalName, jvmDescriptor)
|
||||
fun signature(internalName: String, jvmDescriptor: String) = internalName + "." + jvmDescriptor
|
||||
|
||||
fun jvmDescriptor(name: String, vararg parameters: String, ret: String = "V") =
|
||||
jvmDescriptor(name, parameters.asList(), ret)
|
||||
fun jvmDescriptor(name: String, parameters: List<String>, ret: String = "V") =
|
||||
"$name(${parameters.joinToString("") { escapeClassName(it) }})${escapeClassName(internalName = ret)}"
|
||||
|
||||
private fun escapeClassName(internalName: String) = if (internalName.length > 1) "L$internalName;" else internalName
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
|
||||
import org.jetbrains.kotlin.load.java.isFromJavaOrBuiltins
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
fun FunctionDescriptor.computeJvmDescriptor(withReturnType: Boolean = true)
|
||||
= StringBuilder().apply {
|
||||
append(if (this@computeJvmDescriptor is ConstructorDescriptor) "<init>" else name.asString())
|
||||
append("(")
|
||||
|
||||
valueParameters.forEach {
|
||||
appendErasedType(it.type)
|
||||
}
|
||||
|
||||
append(")")
|
||||
|
||||
if (withReturnType) {
|
||||
if (hasVoidReturnType(this@computeJvmDescriptor)) {
|
||||
append("V")
|
||||
}
|
||||
else {
|
||||
appendErasedType(returnType!!)
|
||||
}
|
||||
}
|
||||
}.toString()
|
||||
|
||||
// Boxing is only necessary for 'remove(E): Boolean' of a MutableCollection<Int> implementation
|
||||
// Otherwise this method might clash with 'remove(I): E' defined in the java.util.List JDK interface (mapped to kotlin 'removeAt')
|
||||
fun forceSingleValueParameterBoxing(f: CallableDescriptor): Boolean {
|
||||
if (f !is FunctionDescriptor) return false
|
||||
|
||||
if (f.valueParameters.size != 1 || f.isFromJavaOrBuiltins() || f.name.asString() != "remove") return false
|
||||
if ((f.original.valueParameters.single().type.mapToJvmType() as? JvmType.Primitive)?.jvmPrimitiveType != JvmPrimitiveType.INT) return false
|
||||
|
||||
val overridden =
|
||||
BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(f)
|
||||
?: return false
|
||||
|
||||
val overriddenParameterType = overridden.original.valueParameters.single().type.mapToJvmType()
|
||||
return overridden.containingDeclaration.fqNameUnsafe == KotlinBuiltIns.FQ_NAMES.mutableCollection.toUnsafe()
|
||||
&& overriddenParameterType is JvmType.Object && overriddenParameterType.internalName == "java/lang/Object"
|
||||
}
|
||||
|
||||
// This method only returns not-null for class methods
|
||||
internal fun CallableDescriptor.computeJvmSignature(): String? = signatures {
|
||||
if (DescriptorUtils.isLocal(this@computeJvmSignature)) return null
|
||||
|
||||
val classDescriptor = containingDeclaration as? ClassDescriptor ?: return null
|
||||
if (classDescriptor.name.isSpecial) return null
|
||||
|
||||
signature(
|
||||
classDescriptor,
|
||||
(original as? SimpleFunctionDescriptor ?: return null).computeJvmDescriptor()
|
||||
)
|
||||
}
|
||||
|
||||
internal val ClassDescriptor.internalName: String
|
||||
get() {
|
||||
JavaToKotlinClassMap.mapKotlinToJava(fqNameSafe.toUnsafe())?.let {
|
||||
return JvmClassName.byClassId(it).internalName
|
||||
}
|
||||
|
||||
return computeInternalName(this)
|
||||
}
|
||||
|
||||
internal val ClassId.internalName: String
|
||||
get() {
|
||||
return JvmClassName.byClassId(JavaToKotlinClassMap.mapKotlinToJava(asSingleFqName().toUnsafe()) ?: this).internalName
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendErasedType(type: KotlinType) {
|
||||
append(type.mapToJvmType())
|
||||
}
|
||||
|
||||
internal fun KotlinType.mapToJvmType() =
|
||||
mapType(this, JvmTypeFactoryImpl, TypeMappingMode.DEFAULT, TypeMappingConfigurationImpl, descriptorTypeWriter = null)
|
||||
|
||||
sealed class JvmType {
|
||||
// null means 'void'
|
||||
class Primitive(val jvmPrimitiveType: JvmPrimitiveType?) : JvmType()
|
||||
class Object(val internalName: String) : JvmType()
|
||||
class Array(val elementType: JvmType) : JvmType()
|
||||
|
||||
override fun toString() = JvmTypeFactoryImpl.toString(this)
|
||||
}
|
||||
|
||||
private object JvmTypeFactoryImpl : JvmTypeFactory<JvmType> {
|
||||
override fun boxType(possiblyPrimitiveType: JvmType) =
|
||||
when {
|
||||
possiblyPrimitiveType is JvmType.Primitive && possiblyPrimitiveType.jvmPrimitiveType != null ->
|
||||
createObjectType(
|
||||
JvmClassName.byFqNameWithoutInnerClasses(
|
||||
possiblyPrimitiveType.jvmPrimitiveType.wrapperFqName).internalName)
|
||||
else -> possiblyPrimitiveType
|
||||
}
|
||||
|
||||
override fun createFromString(representation: String): JvmType {
|
||||
assert(representation.length > 0) { "empty string as JvmType" }
|
||||
val firstChar = representation[0]
|
||||
|
||||
JvmPrimitiveType.values().firstOrNull { it.desc[0] == firstChar }?.let {
|
||||
return JvmType.Primitive(it)
|
||||
}
|
||||
|
||||
return when (firstChar) {
|
||||
'V' -> JvmType.Primitive(null)
|
||||
'[' -> JvmType.Array(createFromString(representation.substring(1)))
|
||||
else -> {
|
||||
assert(firstChar == 'L' && representation.endsWith(';')) {
|
||||
"Type that is not primitive nor array should be Object, but '$representation' was found"
|
||||
}
|
||||
|
||||
JvmType.Object(representation.substring(1, representation.length - 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun createObjectType(internalName: String) = JvmType.Object(internalName)
|
||||
|
||||
override fun toString(type: JvmType): String =
|
||||
when (type) {
|
||||
is JvmType.Array -> "[" + toString(type.elementType)
|
||||
is JvmType.Primitive -> type.jvmPrimitiveType?.desc ?: "V"
|
||||
is JvmType.Object -> "L" + type.internalName + ";"
|
||||
}
|
||||
|
||||
override val javaLangClassType: JvmType
|
||||
get() = createObjectType("java/lang/Class")
|
||||
|
||||
}
|
||||
|
||||
internal object TypeMappingConfigurationImpl : TypeMappingConfiguration<JvmType> {
|
||||
override fun commonSupertype(types: Collection<KotlinType>): KotlinType {
|
||||
throw AssertionError("There should be no intersection type in existing descriptors, but found: " + types.joinToString())
|
||||
}
|
||||
|
||||
override fun getPredefinedTypeForClass(classDescriptor: ClassDescriptor) = null
|
||||
override fun getPredefinedInternalNameForClass(classDescriptor: ClassDescriptor): String? = null
|
||||
|
||||
override fun processErrorType(kotlinType: KotlinType, descriptor: ClassDescriptor) {
|
||||
// DO nothing
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.builtins.FAKE_CONTINUATION_CLASS_DESCRIPTOR
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
|
||||
import org.jetbrains.kotlin.builtins.transformSuspendFunctionToRuntimeFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.hasEnhancedNullability
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
|
||||
import org.jetbrains.kotlin.utils.DO_NOTHING_3
|
||||
|
||||
interface JvmTypeFactory<T : Any> {
|
||||
fun boxType(possiblyPrimitiveType: T): T
|
||||
fun createFromString(representation: String): T
|
||||
fun createObjectType(internalName: String): T
|
||||
fun toString(type: T): String
|
||||
|
||||
val javaLangClassType: T
|
||||
}
|
||||
|
||||
private fun <T : Any> JvmTypeFactory<T>.boxTypeIfNeeded(possiblyPrimitiveType: T, needBoxedType: Boolean) =
|
||||
if (needBoxedType) boxType(possiblyPrimitiveType) else possiblyPrimitiveType
|
||||
|
||||
interface TypeMappingConfiguration<out T : Any> {
|
||||
private companion object {
|
||||
private val DEFAULT_INNER_CLASS_NAME_FACTORY = fun(outer: String, inner: String) = outer + "$" + inner
|
||||
}
|
||||
|
||||
val innerClassNameFactory: (outer: String, inner: String) -> String
|
||||
get() = DEFAULT_INNER_CLASS_NAME_FACTORY
|
||||
|
||||
fun commonSupertype(types: Collection<@JvmSuppressWildcards KotlinType>): KotlinType
|
||||
fun getPredefinedTypeForClass(classDescriptor: ClassDescriptor): T?
|
||||
fun getPredefinedInternalNameForClass(classDescriptor: ClassDescriptor): String?
|
||||
fun processErrorType(kotlinType: KotlinType, descriptor: ClassDescriptor)
|
||||
}
|
||||
|
||||
const val NON_EXISTENT_CLASS_NAME = "error/NonExistentClass"
|
||||
|
||||
private val CONTINUATION_INTERNAL_NAME =
|
||||
JvmClassName.byClassId(ClassId.topLevel(DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME)).internalName
|
||||
|
||||
fun <T : Any> mapType(
|
||||
kotlinType: KotlinType,
|
||||
factory: JvmTypeFactory<T>,
|
||||
mode: TypeMappingMode,
|
||||
typeMappingConfiguration: TypeMappingConfiguration<T>,
|
||||
descriptorTypeWriter: JvmDescriptorTypeWriter<T>?,
|
||||
writeGenericType: (KotlinType, T, TypeMappingMode) -> Unit = DO_NOTHING_3
|
||||
): T {
|
||||
if (kotlinType.isSuspendFunctionType) {
|
||||
return mapType(
|
||||
transformSuspendFunctionToRuntimeFunctionType(kotlinType),
|
||||
factory, mode, typeMappingConfiguration, descriptorTypeWriter,
|
||||
writeGenericType
|
||||
)
|
||||
}
|
||||
|
||||
mapBuiltInType(kotlinType, factory, mode, typeMappingConfiguration)?.let { builtInType ->
|
||||
val jvmType = factory.boxTypeIfNeeded(builtInType, mode.needPrimitiveBoxing)
|
||||
writeGenericType(kotlinType, jvmType, mode)
|
||||
return jvmType
|
||||
}
|
||||
|
||||
val constructor = kotlinType.constructor
|
||||
if (constructor is IntersectionTypeConstructor) {
|
||||
val commonSupertype = typeMappingConfiguration.commonSupertype(constructor.supertypes)
|
||||
// interface In<in E>
|
||||
// open class A : In<A>
|
||||
// open class B : In<B>
|
||||
// commonSupertype(A, B) = In<A & B>
|
||||
// So replace arguments with star-projections to prevent infinite recursive mapping
|
||||
// It's not very important because such types anyway are prohibited in declarations
|
||||
return mapType(
|
||||
commonSupertype.replaceArgumentsWithStarProjections(),
|
||||
factory, mode, typeMappingConfiguration, descriptorTypeWriter, writeGenericType)
|
||||
}
|
||||
|
||||
val descriptor =
|
||||
constructor.declarationDescriptor
|
||||
?: throw UnsupportedOperationException("no descriptor for type constructor of " + kotlinType)
|
||||
|
||||
when {
|
||||
ErrorUtils.isError(descriptor) -> {
|
||||
val jvmType = factory.createObjectType(NON_EXISTENT_CLASS_NAME)
|
||||
typeMappingConfiguration.processErrorType(kotlinType, descriptor as ClassDescriptor)
|
||||
descriptorTypeWriter?.writeClass(jvmType)
|
||||
return jvmType
|
||||
}
|
||||
|
||||
descriptor is ClassDescriptor && KotlinBuiltIns.isArray(kotlinType) -> {
|
||||
if (kotlinType.arguments.size != 1) {
|
||||
throw UnsupportedOperationException("arrays must have one type argument")
|
||||
}
|
||||
val memberProjection = kotlinType.arguments[0]
|
||||
val memberType = memberProjection.type
|
||||
|
||||
val arrayElementType: T
|
||||
if (memberProjection.projectionKind === Variance.IN_VARIANCE) {
|
||||
arrayElementType = factory.createObjectType("java/lang/Object")
|
||||
descriptorTypeWriter?.apply {
|
||||
writeArrayType()
|
||||
writeClass(arrayElementType)
|
||||
writeArrayEnd()
|
||||
}
|
||||
}
|
||||
else {
|
||||
descriptorTypeWriter?.writeArrayType()
|
||||
|
||||
arrayElementType =
|
||||
mapType(
|
||||
memberType, factory,
|
||||
mode.toGenericArgumentMode(memberProjection.projectionKind),
|
||||
typeMappingConfiguration, descriptorTypeWriter, writeGenericType)
|
||||
|
||||
descriptorTypeWriter?.writeArrayEnd()
|
||||
}
|
||||
|
||||
return factory.createFromString("[" + factory.toString(arrayElementType))
|
||||
}
|
||||
|
||||
descriptor is ClassDescriptor -> {
|
||||
val jvmType =
|
||||
if (mode.isForAnnotationParameter && KotlinBuiltIns.isKClass(descriptor)) {
|
||||
factory.javaLangClassType
|
||||
}
|
||||
else {
|
||||
typeMappingConfiguration.getPredefinedTypeForClass(descriptor.original)
|
||||
?: run {
|
||||
// refer to enum entries by enum type in bytecode unless ASM_TYPE is written
|
||||
val enumClassIfEnumEntry = if (descriptor.kind == ClassKind.ENUM_ENTRY)
|
||||
descriptor.containingDeclaration as ClassDescriptor
|
||||
else descriptor
|
||||
factory.createObjectType(computeInternalName(enumClassIfEnumEntry.original, typeMappingConfiguration))
|
||||
}
|
||||
}
|
||||
|
||||
writeGenericType(kotlinType, jvmType, mode)
|
||||
|
||||
return jvmType
|
||||
}
|
||||
|
||||
descriptor is TypeParameterDescriptor -> {
|
||||
val type = mapType(getRepresentativeUpperBound(descriptor),
|
||||
factory, mode, typeMappingConfiguration, writeGenericType = DO_NOTHING_3, descriptorTypeWriter = null)
|
||||
descriptorTypeWriter?.writeTypeVariable(descriptor.getName(), type)
|
||||
return type
|
||||
}
|
||||
|
||||
else -> throw UnsupportedOperationException("Unknown type " + kotlinType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun hasVoidReturnType(descriptor: CallableDescriptor): Boolean {
|
||||
if (descriptor is ConstructorDescriptor) return true
|
||||
return KotlinBuiltIns.isUnit(descriptor.returnType!!) && !TypeUtils.isNullableType(descriptor.returnType!!)
|
||||
&& descriptor !is PropertyGetterDescriptor
|
||||
}
|
||||
|
||||
private fun <T : Any> mapBuiltInType(
|
||||
type: KotlinType,
|
||||
typeFactory: JvmTypeFactory<T>,
|
||||
mode: TypeMappingMode,
|
||||
typeMappingConfiguration: TypeMappingConfiguration<T>
|
||||
): T? {
|
||||
val descriptor = type.constructor.declarationDescriptor as? ClassDescriptor ?: return null
|
||||
|
||||
if (descriptor === FAKE_CONTINUATION_CLASS_DESCRIPTOR) {
|
||||
|
||||
return typeFactory.createObjectType(CONTINUATION_INTERNAL_NAME)
|
||||
}
|
||||
|
||||
val primitiveType = KotlinBuiltIns.getPrimitiveType(descriptor)
|
||||
if (primitiveType != null) {
|
||||
val jvmType = typeFactory.createFromString(JvmPrimitiveType.get(primitiveType).desc)
|
||||
val isNullableInJava = TypeUtils.isNullableType(type) || type.hasEnhancedNullability()
|
||||
return typeFactory.boxTypeIfNeeded(jvmType, isNullableInJava)
|
||||
}
|
||||
|
||||
val arrayElementType = KotlinBuiltIns.getPrimitiveArrayType(descriptor)
|
||||
if (arrayElementType != null) {
|
||||
return typeFactory.createFromString("[" + JvmPrimitiveType.get(arrayElementType).desc)
|
||||
}
|
||||
|
||||
if (KotlinBuiltIns.isUnderKotlinPackage(descriptor)) {
|
||||
val classId = JavaToKotlinClassMap.mapKotlinToJava(descriptor.fqNameUnsafe)
|
||||
if (classId != null) {
|
||||
if (!mode.kotlinCollectionsToJavaCollections &&
|
||||
JavaToKotlinClassMap.mutabilityMappings.any { it.javaClass == classId }) return null
|
||||
|
||||
return typeFactory.createObjectType(JvmClassName.byClassId(classId, typeMappingConfiguration).internalName)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun computeInternalName(
|
||||
klass: ClassDescriptor,
|
||||
typeMappingConfiguration: TypeMappingConfiguration<*> = TypeMappingConfigurationImpl
|
||||
): String {
|
||||
val container = klass.containingDeclaration
|
||||
|
||||
val name = SpecialNames.safeIdentifier(klass.name).identifier
|
||||
if (container is PackageFragmentDescriptor) {
|
||||
val fqName = container.fqName
|
||||
return if (fqName.isRoot) name else fqName.asString().replace('.', '/') + '/' + name
|
||||
}
|
||||
|
||||
val containerClass = container as? ClassDescriptor ?:
|
||||
throw IllegalArgumentException("Unexpected container: $container for $klass")
|
||||
|
||||
val containerInternalName =
|
||||
typeMappingConfiguration.getPredefinedInternalNameForClass(containerClass) ?:
|
||||
computeInternalName(containerClass, typeMappingConfiguration)
|
||||
return typeMappingConfiguration.innerClassNameFactory(containerInternalName, name)
|
||||
}
|
||||
|
||||
private fun getRepresentativeUpperBound(descriptor: TypeParameterDescriptor): KotlinType {
|
||||
val upperBounds = descriptor.upperBounds
|
||||
assert(!upperBounds.isEmpty()) { "Upper bounds should not be empty: " + descriptor }
|
||||
|
||||
return upperBounds.firstOrNull {
|
||||
val classDescriptor = it.constructor.declarationDescriptor as? ClassDescriptor ?: return@firstOrNull false
|
||||
classDescriptor.kind != ClassKind.INTERFACE && classDescriptor.kind != ClassKind.ANNOTATION_CLASS
|
||||
} ?: upperBounds.first()
|
||||
}
|
||||
|
||||
open class JvmDescriptorTypeWriter<T : Any>(private val jvmTypeFactory: JvmTypeFactory<T>) {
|
||||
private var jvmCurrentTypeArrayLevel: Int = 0
|
||||
protected var jvmCurrentType: T? = null
|
||||
private set
|
||||
|
||||
protected fun clearCurrentType() {
|
||||
jvmCurrentType = null
|
||||
jvmCurrentTypeArrayLevel = 0
|
||||
}
|
||||
|
||||
open fun writeArrayType() {
|
||||
if (jvmCurrentType == null) {
|
||||
++jvmCurrentTypeArrayLevel
|
||||
}
|
||||
}
|
||||
|
||||
open fun writeArrayEnd() {
|
||||
}
|
||||
|
||||
|
||||
open public fun writeClass(objectType: T) {
|
||||
writeJvmTypeAsIs(objectType)
|
||||
}
|
||||
|
||||
protected fun writeJvmTypeAsIs(type: T) {
|
||||
if (jvmCurrentType == null) {
|
||||
jvmCurrentType = jvmTypeFactory.createFromString("[".repeat(jvmCurrentTypeArrayLevel) + jvmTypeFactory.toString(type))
|
||||
}
|
||||
}
|
||||
|
||||
open fun writeTypeVariable(name: Name, type: T) {
|
||||
writeJvmTypeAsIs(type)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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.platform
|
||||
|
||||
import org.jetbrains.kotlin.builtins.CompanionObjectMapping
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.name.*
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import java.util.*
|
||||
|
||||
object JavaToKotlinClassMap : PlatformToKotlinClassMap {
|
||||
|
||||
private val javaToKotlin = HashMap<FqNameUnsafe, ClassId>()
|
||||
private val kotlinToJava = HashMap<FqNameUnsafe, ClassId>()
|
||||
|
||||
private val mutableToReadOnly = HashMap<FqNameUnsafe, FqName>()
|
||||
private val readOnlyToMutable = HashMap<FqNameUnsafe, FqName>()
|
||||
|
||||
// describes mapping for a java class that has separate readOnly and mutable equivalents in Kotlin
|
||||
data class PlatformMutabilityMapping(
|
||||
val javaClass: ClassId,
|
||||
val kotlinReadOnly: ClassId,
|
||||
val kotlinMutable: ClassId
|
||||
)
|
||||
|
||||
private inline fun <reified T> mutabilityMapping(kotlinReadOnly: ClassId, kotlinMutable: FqName): PlatformMutabilityMapping {
|
||||
val mutableClassId = ClassId(kotlinReadOnly.packageFqName, kotlinMutable.tail(kotlinReadOnly.packageFqName), false)
|
||||
return PlatformMutabilityMapping(classId(T::class.java), kotlinReadOnly, mutableClassId)
|
||||
}
|
||||
|
||||
val mutabilityMappings = listOf(
|
||||
mutabilityMapping<Iterable<*>>(ClassId.topLevel(FQ_NAMES.iterable), FQ_NAMES.mutableIterable),
|
||||
mutabilityMapping<Iterator<*>>(ClassId.topLevel(FQ_NAMES.iterator), FQ_NAMES.mutableIterator),
|
||||
mutabilityMapping<Collection<*>>(ClassId.topLevel(FQ_NAMES.collection), FQ_NAMES.mutableCollection),
|
||||
mutabilityMapping<List<*>>(ClassId.topLevel(FQ_NAMES.list), FQ_NAMES.mutableList),
|
||||
mutabilityMapping<Set<*>>(ClassId.topLevel(FQ_NAMES.set), FQ_NAMES.mutableSet),
|
||||
mutabilityMapping<ListIterator<*>>(ClassId.topLevel(FQ_NAMES.listIterator), FQ_NAMES.mutableListIterator),
|
||||
mutabilityMapping<Map<*, *>>(ClassId.topLevel(FQ_NAMES.map), FQ_NAMES.mutableMap),
|
||||
mutabilityMapping<Map.Entry<*, *>>(
|
||||
ClassId.topLevel(FQ_NAMES.map).createNestedClassId(FQ_NAMES.mapEntry.shortName()), FQ_NAMES.mutableMapEntry
|
||||
)
|
||||
)
|
||||
|
||||
init {
|
||||
addTopLevel(Any::class.java, FQ_NAMES.any)
|
||||
addTopLevel(String::class.java, FQ_NAMES.string)
|
||||
addTopLevel(CharSequence::class.java, FQ_NAMES.charSequence)
|
||||
addTopLevel(Throwable::class.java, FQ_NAMES.throwable)
|
||||
addTopLevel(Cloneable::class.java, FQ_NAMES.cloneable)
|
||||
addTopLevel(Number::class.java, FQ_NAMES.number)
|
||||
addTopLevel(Comparable::class.java, FQ_NAMES.comparable)
|
||||
addTopLevel(Enum::class.java, FQ_NAMES._enum)
|
||||
addTopLevel(Annotation::class.java, FQ_NAMES.annotation)
|
||||
|
||||
for (platformCollection in mutabilityMappings) {
|
||||
addMapping(platformCollection)
|
||||
}
|
||||
|
||||
for (jvmType in JvmPrimitiveType.values()) {
|
||||
add(ClassId.topLevel(jvmType.wrapperFqName),
|
||||
ClassId.topLevel(KotlinBuiltIns.getPrimitiveFqName(jvmType.primitiveType)))
|
||||
}
|
||||
|
||||
for (classId in CompanionObjectMapping.allClassesWithIntrinsicCompanions()) {
|
||||
add(ClassId.topLevel(FqName("kotlin.jvm.internal." + classId.shortClassName.asString() + "CompanionObject")),
|
||||
classId.createNestedClassId(SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT))
|
||||
}
|
||||
|
||||
// TODO: support also functions with >= 23 parameters
|
||||
for (i in 0..22) {
|
||||
add(ClassId.topLevel(FqName("kotlin.jvm.functions.Function" + i)), KotlinBuiltIns.getFunctionClassId(i))
|
||||
|
||||
val kFunction = FunctionClassDescriptor.Kind.KFunction
|
||||
val kFun = kFunction.packageFqName.toString() + "." + kFunction.classNamePrefix
|
||||
addKotlinToJava(FqName(kFun + i), ClassId.topLevel(FqName(kFun)))
|
||||
}
|
||||
|
||||
addKotlinToJava(FQ_NAMES.nothing.toSafe(), classId(Void::class.java))
|
||||
}
|
||||
|
||||
/**
|
||||
* E.g.
|
||||
* java.lang.String -> kotlin.String
|
||||
* java.lang.Integer -> kotlin.Int
|
||||
* kotlin.jvm.internal.IntCompanionObject -> kotlin.Int.Companion
|
||||
* java.util.List -> kotlin.List
|
||||
* java.util.Map.Entry -> kotlin.Map.Entry
|
||||
* java.lang.Void -> null
|
||||
* kotlin.jvm.functions.Function3 -> kotlin.Function3
|
||||
*/
|
||||
fun mapJavaToKotlin(fqName: FqName): ClassId? {
|
||||
return javaToKotlin[fqName.toUnsafe()]
|
||||
}
|
||||
|
||||
fun mapJavaToKotlin(fqName: FqName, builtIns: KotlinBuiltIns): ClassDescriptor? {
|
||||
val kotlinClassId = mapJavaToKotlin(fqName)
|
||||
return if (kotlinClassId != null) builtIns.getBuiltInClassByFqName(kotlinClassId.asSingleFqName()) else null
|
||||
}
|
||||
|
||||
/**
|
||||
* E.g.
|
||||
* kotlin.Throwable -> java.lang.Throwable
|
||||
* kotlin.Int -> java.lang.Integer
|
||||
* kotlin.Int.Companion -> kotlin.jvm.internal.IntCompanionObject
|
||||
* kotlin.Nothing -> java.lang.Void
|
||||
* kotlin.IntArray -> null
|
||||
* kotlin.Function3 -> kotlin.jvm.functions.Function3
|
||||
* kotlin.reflect.KFunction3 -> kotlin.reflect.KFunction
|
||||
*/
|
||||
fun mapKotlinToJava(kotlinFqName: FqNameUnsafe): ClassId? {
|
||||
return kotlinToJava[kotlinFqName]
|
||||
}
|
||||
|
||||
private fun addMapping(platformMutabilityMapping: PlatformMutabilityMapping) {
|
||||
val (javaClassId, readOnlyClassId, mutableClassId) = platformMutabilityMapping
|
||||
add(javaClassId, readOnlyClassId)
|
||||
addKotlinToJava(mutableClassId.asSingleFqName(), javaClassId)
|
||||
|
||||
val readOnlyFqName = readOnlyClassId.asSingleFqName()
|
||||
val mutableFqName = mutableClassId.asSingleFqName()
|
||||
mutableToReadOnly.put(mutableClassId.asSingleFqName().toUnsafe(), readOnlyFqName)
|
||||
readOnlyToMutable.put(readOnlyFqName.toUnsafe(), mutableFqName)
|
||||
}
|
||||
|
||||
private fun add(javaClassId: ClassId, kotlinClassId: ClassId) {
|
||||
addJavaToKotlin(javaClassId, kotlinClassId)
|
||||
addKotlinToJava(kotlinClassId.asSingleFqName(), javaClassId)
|
||||
}
|
||||
|
||||
private fun addTopLevel(javaClass: Class<*>, kotlinFqName: FqNameUnsafe) {
|
||||
addTopLevel(javaClass, kotlinFqName.toSafe())
|
||||
}
|
||||
|
||||
private fun addTopLevel(javaClass: Class<*>, kotlinFqName: FqName) {
|
||||
add(classId(javaClass), ClassId.topLevel(kotlinFqName))
|
||||
}
|
||||
|
||||
private fun addJavaToKotlin(javaClassId: ClassId, kotlinClassId: ClassId) {
|
||||
javaToKotlin.put(javaClassId.asSingleFqName().toUnsafe(), kotlinClassId)
|
||||
}
|
||||
|
||||
private fun addKotlinToJava(kotlinFqNameUnsafe: FqName, javaClassId: ClassId) {
|
||||
kotlinToJava.put(kotlinFqNameUnsafe.toUnsafe(), javaClassId)
|
||||
}
|
||||
|
||||
fun isJavaPlatformClass(fqName: FqName): Boolean = mapJavaToKotlin(fqName) != null
|
||||
|
||||
fun mapPlatformClass(fqName: FqName, builtIns: KotlinBuiltIns): Collection<ClassDescriptor> {
|
||||
val kotlinAnalog = mapJavaToKotlin(fqName, builtIns) ?: return emptySet()
|
||||
|
||||
val kotlinMutableAnalogFqName = readOnlyToMutable[kotlinAnalog.fqNameUnsafe] ?: return setOf(kotlinAnalog)
|
||||
|
||||
return Arrays.asList(kotlinAnalog, builtIns.getBuiltInClassByFqName(kotlinMutableAnalogFqName))
|
||||
}
|
||||
|
||||
override fun mapPlatformClass(classDescriptor: ClassDescriptor): Collection<ClassDescriptor> {
|
||||
val className = DescriptorUtils.getFqName(classDescriptor)
|
||||
return if (className.isSafe)
|
||||
mapPlatformClass(className.toSafe(), classDescriptor.builtIns)
|
||||
else
|
||||
emptySet<ClassDescriptor>()
|
||||
}
|
||||
|
||||
fun isMutable(mutable: ClassDescriptor): Boolean = mutableToReadOnly.containsKey(DescriptorUtils.getFqName(mutable))
|
||||
|
||||
fun isMutable(type: KotlinType): Boolean {
|
||||
val classDescriptor = TypeUtils.getClassDescriptor(type)
|
||||
return classDescriptor != null && isMutable(classDescriptor)
|
||||
}
|
||||
|
||||
fun isReadOnly(readOnly: ClassDescriptor): Boolean = readOnlyToMutable.containsKey(DescriptorUtils.getFqName(readOnly))
|
||||
|
||||
fun isReadOnly(type: KotlinType): Boolean {
|
||||
val classDescriptor = TypeUtils.getClassDescriptor(type)
|
||||
return classDescriptor != null && isReadOnly(classDescriptor)
|
||||
}
|
||||
|
||||
fun convertMutableToReadOnly(mutable: ClassDescriptor): ClassDescriptor {
|
||||
return convertToOppositeMutability(mutable, mutableToReadOnly, "mutable")
|
||||
}
|
||||
|
||||
fun convertReadOnlyToMutable(readOnly: ClassDescriptor): ClassDescriptor {
|
||||
return convertToOppositeMutability(readOnly, readOnlyToMutable, "read-only")
|
||||
}
|
||||
|
||||
private fun classId(clazz: Class<*>): ClassId {
|
||||
assert(!clazz.isPrimitive && !clazz.isArray) { "Invalid class: " + clazz }
|
||||
val outer = clazz.declaringClass
|
||||
return if (outer == null)
|
||||
ClassId.topLevel(FqName(clazz.canonicalName))
|
||||
else
|
||||
classId(outer).createNestedClassId(Name.identifier(clazz.simpleName))
|
||||
}
|
||||
|
||||
private fun convertToOppositeMutability(
|
||||
descriptor: ClassDescriptor,
|
||||
map: Map<FqNameUnsafe, FqName>,
|
||||
mutabilityKindName: String
|
||||
): ClassDescriptor {
|
||||
val oppositeClassFqName = map[DescriptorUtils.getFqName(descriptor)] ?: throw IllegalArgumentException("Given class $descriptor is not a $mutabilityKindName collection")
|
||||
return descriptor.builtIns.getBuiltInClassByFqName(oppositeClassFqName)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.platform
|
||||
|
||||
import org.jetbrains.kotlin.builtins.JvmBuiltInClassDescriptorFactory
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.AdditionalClassPartsProvider
|
||||
import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclarationFilter
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmBuiltInsSettings
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
|
||||
class JvmBuiltIns @JvmOverloads constructor(
|
||||
storageManager: StorageManager,
|
||||
loadBuiltInsFromCurrentClassLoader: Boolean = true
|
||||
) : KotlinBuiltIns(storageManager) {
|
||||
// Module containing JDK classes or having them among dependencies
|
||||
private var ownerModuleDescriptor: ModuleDescriptor? = null
|
||||
private var isAdditionalBuiltInsFeatureSupported: Boolean = true
|
||||
|
||||
fun initialize(moduleDescriptor: ModuleDescriptor, isAdditionalBuiltInsFeatureSupported: Boolean) {
|
||||
assert(ownerModuleDescriptor == null) { "JvmBuiltins repeated initialization" }
|
||||
this.ownerModuleDescriptor = moduleDescriptor
|
||||
this.isAdditionalBuiltInsFeatureSupported = isAdditionalBuiltInsFeatureSupported
|
||||
}
|
||||
|
||||
val settings: JvmBuiltInsSettings by storageManager.createLazyValue {
|
||||
JvmBuiltInsSettings(
|
||||
builtInsModule, storageManager,
|
||||
{ ownerModuleDescriptor.sure { "JvmBuiltins has not been initialized properly" } },
|
||||
{
|
||||
ownerModuleDescriptor.sure { "JvmBuiltins has not been initialized properly" }
|
||||
isAdditionalBuiltInsFeatureSupported
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
init {
|
||||
if (loadBuiltInsFromCurrentClassLoader) {
|
||||
createBuiltInsModule()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPlatformDependentDeclarationFilter(): PlatformDependentDeclarationFilter = settings
|
||||
|
||||
override fun getAdditionalClassPartsProvider(): AdditionalClassPartsProvider = settings
|
||||
|
||||
override fun getClassDescriptorFactories() =
|
||||
super.getClassDescriptorFactories() + JvmBuiltInClassDescriptorFactory(storageManager, builtInsModule)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.platform
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
|
||||
fun createMappedTypeParametersSubstitution(from: ClassDescriptor, to: ClassDescriptor): TypeConstructorSubstitution {
|
||||
assert(from.declaredTypeParameters.size == to.declaredTypeParameters.size) {
|
||||
"$from and $to should have same number of type parameters, " +
|
||||
"but ${from.declaredTypeParameters.size} / ${to.declaredTypeParameters.size} found"
|
||||
}
|
||||
|
||||
return TypeConstructorSubstitution.createByConstructorsMap(
|
||||
from.declaredTypeParameters.map(TypeParameterDescriptor::getTypeConstructor).zip(
|
||||
to.declaredTypeParameters.map { it.defaultType.asTypeProjection() }
|
||||
).toMap())
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.resolve.jvm
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.components.JavaResolverCache
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaPackageFragmentProvider
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
|
||||
|
||||
class JavaDescriptorResolver(
|
||||
val packageFragmentProvider: LazyJavaPackageFragmentProvider,
|
||||
private val javaResolverCache: JavaResolverCache
|
||||
) {
|
||||
fun resolveClass(javaClass: JavaClass): ClassDescriptor? {
|
||||
val fqName = javaClass.fqName
|
||||
if (fqName != null && javaClass.lightClassOriginKind == LightClassOriginKind.SOURCE) {
|
||||
return javaResolverCache.getClassResolvedFromSource(fqName)
|
||||
}
|
||||
|
||||
javaClass.outerClass?.let { outerClass ->
|
||||
val outerClassScope = resolveClass(outerClass)?.unsubstitutedInnerClassesScope
|
||||
return outerClassScope?.getContributedClassifier(javaClass.name, NoLookupLocation.FROM_JAVA_LOADER) as? ClassDescriptor
|
||||
}
|
||||
|
||||
if (fqName == null) return null
|
||||
|
||||
return packageFragmentProvider.getPackageFragments(fqName.parent()).firstOrNull()?.findClassifierByJavaClass(javaClass)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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.resolve.jvm;
|
||||
|
||||
import kotlin.jvm.functions.Function2;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingConfiguration;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class JvmClassName {
|
||||
@NotNull
|
||||
public static JvmClassName byInternalName(@NotNull String internalName) {
|
||||
return new JvmClassName(internalName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JvmClassName byClassId(@NotNull ClassId classId) {
|
||||
return byClassId(classId, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JvmClassName byClassId(@NotNull ClassId classId, @Nullable TypeMappingConfiguration<?> typeMappingConfiguration) {
|
||||
FqName packageFqName = classId.getPackageFqName();
|
||||
|
||||
String[] relativeClassNameSegments = classId.getRelativeClassName().asString().split(Pattern.quote("."));
|
||||
String relativeClassName;
|
||||
|
||||
if (relativeClassNameSegments.length == 1) {
|
||||
relativeClassName = relativeClassNameSegments[0];
|
||||
}
|
||||
else if (relativeClassNameSegments.length > 1 && typeMappingConfiguration != null) {
|
||||
Function2<String, String, String> innerClassNameFactory = typeMappingConfiguration.getInnerClassNameFactory();
|
||||
relativeClassName = innerClassNameFactory.invoke(relativeClassNameSegments[0], relativeClassNameSegments[1]);
|
||||
for (int i = 2; i < relativeClassNameSegments.length; ++i) {
|
||||
relativeClassName = innerClassNameFactory.invoke(relativeClassName, relativeClassNameSegments[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Default behavior if we don't have an inner class name factory
|
||||
relativeClassName = classId.getRelativeClassName().asString().replace('.', '$');
|
||||
}
|
||||
|
||||
return packageFqName.isRoot()
|
||||
? new JvmClassName(relativeClassName)
|
||||
: new JvmClassName(packageFqName.asString().replace('.', '/') + "/" + relativeClassName);
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: fq name cannot be uniquely mapped to JVM class name.
|
||||
*/
|
||||
@NotNull
|
||||
public static JvmClassName byFqNameWithoutInnerClasses(@NotNull FqName fqName) {
|
||||
JvmClassName r = new JvmClassName(fqName.asString().replace('.', '/'));
|
||||
r.fqName = fqName;
|
||||
return r;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JvmClassName byFqNameWithoutInnerClasses(@NotNull String fqName) {
|
||||
return byFqNameWithoutInnerClasses(new FqName(fqName));
|
||||
}
|
||||
|
||||
// Internal name: kotlin/Map$Entry
|
||||
// FqName: kotlin.Map.Entry
|
||||
|
||||
private final String internalName;
|
||||
private FqName fqName;
|
||||
|
||||
private JvmClassName(@NotNull String internalName) {
|
||||
this.internalName = internalName;
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: internal name cannot be reliably converted to FQ name.
|
||||
*
|
||||
* This method treats all dollar characters ('$') in the internal name as inner class separators.
|
||||
* So it _will work incorrectly_ for classes where dollar characters are a part of the identifier.
|
||||
*
|
||||
* E.g. JvmClassName("org/foo/bar/Baz$quux").getFqNameForClassNameWithoutDollars() -> FqName("org.foo.bar.Baz.quux")
|
||||
*/
|
||||
@NotNull
|
||||
public FqName getFqNameForClassNameWithoutDollars() {
|
||||
if (fqName == null) {
|
||||
this.fqName = new FqName(internalName.replace('$', '.').replace('/', '.'));
|
||||
}
|
||||
return fqName;
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING: internal name cannot be reliably converted to FQ name.
|
||||
*
|
||||
* This method treats all dollar characters ('$') in the internal name as a part of the identifier.
|
||||
* So it _will work incorrectly_ for inner classes.
|
||||
*
|
||||
* E.g. JvmClassName("org/foo/bar/Baz$quux").getFqNameForTopLevelClassMaybeWithDollars() -> FqName("org.foo.bar.Baz$quux")
|
||||
*/
|
||||
@NotNull
|
||||
public FqName getFqNameForTopLevelClassMaybeWithDollars() {
|
||||
return new FqName(internalName.replace('/', '.'));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FqName getPackageFqName() {
|
||||
int lastSlash = internalName.lastIndexOf("/");
|
||||
if (lastSlash == -1) return FqName.ROOT;
|
||||
return new FqName(internalName.substring(0, lastSlash).replace('/', '.'));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getInternalName() {
|
||||
return internalName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return internalName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
return internalName.equals(((JvmClassName) o).internalName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return internalName.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.resolve.jvm;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public enum JvmPrimitiveType {
|
||||
BOOLEAN(PrimitiveType.BOOLEAN, "boolean", "Z", "java.lang.Boolean"),
|
||||
CHAR(PrimitiveType.CHAR, "char", "C", "java.lang.Character"),
|
||||
BYTE(PrimitiveType.BYTE, "byte", "B", "java.lang.Byte"),
|
||||
SHORT(PrimitiveType.SHORT, "short", "S", "java.lang.Short"),
|
||||
INT(PrimitiveType.INT, "int", "I", "java.lang.Integer"),
|
||||
FLOAT(PrimitiveType.FLOAT, "float", "F", "java.lang.Float"),
|
||||
LONG(PrimitiveType.LONG, "long", "J", "java.lang.Long"),
|
||||
DOUBLE(PrimitiveType.DOUBLE, "double", "D", "java.lang.Double"),
|
||||
;
|
||||
|
||||
private static final Set<FqName> WRAPPERS_CLASS_NAMES;
|
||||
private static final Map<String, JvmPrimitiveType> TYPE_BY_NAME;
|
||||
private static final Map<PrimitiveType, JvmPrimitiveType> TYPE_BY_PRIMITIVE_TYPE;
|
||||
|
||||
static {
|
||||
WRAPPERS_CLASS_NAMES = new HashSet<FqName>();
|
||||
TYPE_BY_NAME = new HashMap<String, JvmPrimitiveType>();
|
||||
TYPE_BY_PRIMITIVE_TYPE = new EnumMap<PrimitiveType, JvmPrimitiveType>(PrimitiveType.class);
|
||||
|
||||
for (JvmPrimitiveType type : values()) {
|
||||
WRAPPERS_CLASS_NAMES.add(type.getWrapperFqName());
|
||||
TYPE_BY_NAME.put(type.getJavaKeywordName(), type);
|
||||
TYPE_BY_PRIMITIVE_TYPE.put(type.getPrimitiveType(), type);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isWrapperClassName(@NotNull FqName className) {
|
||||
return WRAPPERS_CLASS_NAMES.contains(className);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JvmPrimitiveType get(@NotNull String name) {
|
||||
JvmPrimitiveType result = TYPE_BY_NAME.get(name);
|
||||
if (result == null) {
|
||||
throw new AssertionError("Non-primitive type name passed: " + name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JvmPrimitiveType get(@NotNull PrimitiveType type) {
|
||||
return TYPE_BY_PRIMITIVE_TYPE.get(type);
|
||||
}
|
||||
|
||||
private final PrimitiveType primitiveType;
|
||||
private final String name;
|
||||
private final String desc;
|
||||
private final FqName wrapperFqName;
|
||||
|
||||
JvmPrimitiveType(@NotNull PrimitiveType primitiveType, @NotNull String name, @NotNull String desc, @NotNull String wrapperClassName) {
|
||||
this.primitiveType = primitiveType;
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
this.wrapperFqName = new FqName(wrapperClassName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PrimitiveType getPrimitiveType() {
|
||||
return primitiveType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getJavaKeywordName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FqName getWrapperFqName() {
|
||||
return wrapperFqName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* 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.serialization.jvm;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.serialization.jvm.UtfEncodingKt.MAX_UTF8_INFO_LENGTH;
|
||||
|
||||
public class BitEncoding {
|
||||
private static final boolean FORCE_8TO7_ENCODING = "true".equals(System.getProperty("kotlin.jvm.serialization.use8to7"));
|
||||
|
||||
private static final char _8TO7_MODE_MARKER = (char) -1;
|
||||
|
||||
private BitEncoding() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte array of serialized data to an array of {@code String} satisfying JVM annotation value argument restrictions:
|
||||
* <ol>
|
||||
* <li>Each string's length should be no more than 65535</li>
|
||||
* <li>UTF-8 representation of each string cannot contain bytes in the range 0xf0..0xff</li>
|
||||
* </ol>
|
||||
*/
|
||||
@NotNull
|
||||
public static String[] encodeBytes(@NotNull byte[] data) {
|
||||
// TODO: try both encodings here and choose the best one (with the smallest size)
|
||||
if (!FORCE_8TO7_ENCODING) {
|
||||
return UtfEncodingKt.bytesToStrings(data);
|
||||
}
|
||||
byte[] bytes = encode8to7(data);
|
||||
// Since 0x0 byte is encoded as two bytes in the Modified UTF-8 (0xc0 0x80) and zero is rather common to byte arrays, we increment
|
||||
// every byte by one modulo max byte value, so that the less common value 0x7f will be represented as two bytes instead.
|
||||
addModuloByte(bytes, 1);
|
||||
return splitBytesToStringArray(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte array to another byte array, every element of which is in the range 0x0..0x7f.
|
||||
*
|
||||
* The conversion is equivalent to the following: input bytes are combined into one long bit string. This big string is then split into
|
||||
* groups of 7 bits. Each resulting 7-bit chunk is then converted to a byte (with a leading bit = 0). The last chunk may have less than
|
||||
* 7 bits, it's prepended with zeros to form a byte. The result is then the array of these bytes, each of which is obviously in the
|
||||
* range 0x0..0x7f.
|
||||
*
|
||||
* Suppose the input of 4 bytes is given (bytes are listed from the beginning to the end, each byte from the least significant bit to
|
||||
* the most significant bit, bits within each byte are numbered):
|
||||
*
|
||||
* 01234567 01234567 01234567 01234567
|
||||
*
|
||||
* The output for this kind of input will be of the following form ('#' represents a zero bit):
|
||||
*
|
||||
* 0123456# 7012345# 6701234# 5670123# 4567####
|
||||
*/
|
||||
@NotNull
|
||||
private static byte[] encode8to7(@NotNull byte[] data) {
|
||||
// ceil(data.length * 8 / 7)
|
||||
int resultLength = (data.length * 8 + 6) / 7;
|
||||
byte[] result = new byte[resultLength];
|
||||
|
||||
// We maintain a pointer to the bit in the input, which is represented by two numbers: index of the current byte in the input and
|
||||
// the index of a bit inside this byte (0 is least significant, 7 is most significant)
|
||||
int byteIndex = 0;
|
||||
int bit = 0;
|
||||
|
||||
// Write all resulting bytes except the last one. To do this we need to collect exactly 7 bits, starting from the current, into a
|
||||
// byte. In almost all cases these 7 bits can be collected from two parts: the first is several (at least one) most significant bits
|
||||
// from the current byte, the second is several (maybe zero) least significant bits from the next byte. The special case is when the
|
||||
// current bit is the first (least significant) bit in its byte (bit == 0): then the 7 needed bits are just the 7 least significant
|
||||
// of the current byte.
|
||||
for (int i = 0; i < resultLength - 1; i++) {
|
||||
if (bit == 0) {
|
||||
result[i] = (byte) (data[byteIndex] & 0x7f);
|
||||
bit = 7;
|
||||
continue;
|
||||
}
|
||||
|
||||
int firstPart = (data[byteIndex] & 0xff) >>> bit;
|
||||
int newBit = (bit + 7) & 7;
|
||||
int secondPart = (data[++byteIndex] & ((1 << newBit) - 1)) << 8 - bit;
|
||||
result[i] = (byte) (firstPart + secondPart);
|
||||
bit = newBit;
|
||||
}
|
||||
|
||||
// Write the last byte, which is just several most significant bits of the last byte in the input, padded with zeros
|
||||
if (resultLength > 0) {
|
||||
assert bit != 0 : "The last chunk cannot start from the input byte since otherwise at least one bit will remain unprocessed";
|
||||
assert byteIndex == data.length - 1 : "The last 7-bit chunk should be encoded from the last input byte: " +
|
||||
byteIndex + " != " + (data.length - 1);
|
||||
result[resultLength - 1] = (byte) ((data[byteIndex] & 0xff) >>> bit);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void addModuloByte(@NotNull byte[] data, int increment) {
|
||||
for (int i = 0, n = data.length; i < n; i++) {
|
||||
data[i] = (byte) ((data[i] + increment) & 0x7f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a big byte array into the array of strings, where each string, when written to the constant pool table in bytecode, produces
|
||||
* a byte array of not more than MAX_UTF8_INFO_LENGTH. Each byte, except those which are 0x0, occupies exactly one byte in the constant
|
||||
* pool table. Zero bytes occupy two bytes in the table each.
|
||||
*
|
||||
* When strings are constructed from the array of bytes here, they are encoded in the platform's default encoding. This is fine: the
|
||||
* conversion to the Modified UTF-8 (which here would be equivalent to replacing each 0x0 with 0xc0 0x80) will happen later by ASM, when
|
||||
* it writes these strings to the bytecode
|
||||
*/
|
||||
@NotNull
|
||||
private static String[] splitBytesToStringArray(@NotNull byte[] data) {
|
||||
List<String> result = new ArrayList<String>();
|
||||
|
||||
// The offset where the currently processed string starts
|
||||
int off = 0;
|
||||
|
||||
// The effective length the bytes of the current string would occupy in the constant pool table.
|
||||
// 2 because the first char is -1 which denotes the encoding mode and occupies two bytes in Modified UTF-8
|
||||
int len = 2;
|
||||
|
||||
boolean encodingModeAdded = false;
|
||||
|
||||
for (int i = 0, n = data.length; i < n; i++) {
|
||||
// When the effective length reaches at least MAX - 1, we add the current string to the result. Note that the effective length
|
||||
// is at most MAX here: non-zero bytes occupy 1 byte and zero bytes occupy 2 bytes, so we couldn't jump over more than one byte
|
||||
if (len >= MAX_UTF8_INFO_LENGTH - 1) {
|
||||
assert len <= MAX_UTF8_INFO_LENGTH : "Produced strings cannot contain more than " + MAX_UTF8_INFO_LENGTH + " bytes: " + len;
|
||||
String string = new String(data, off, i - off);
|
||||
if (!encodingModeAdded) {
|
||||
encodingModeAdded = true;
|
||||
result.add(_8TO7_MODE_MARKER + string);
|
||||
}
|
||||
else {
|
||||
result.add(string);
|
||||
}
|
||||
off = i;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
if (data[i] == 0) {
|
||||
len += 2;
|
||||
}
|
||||
else {
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
if (len >= 0) {
|
||||
result.add(new String(data, off, data.length - off));
|
||||
}
|
||||
|
||||
return result.toArray(new String[result.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts encoded array of {@code String} obtained by {@link BitEncoding#encodeBytes(byte[])} back to a byte array.
|
||||
*/
|
||||
@NotNull
|
||||
public static byte[] decodeBytes(@NotNull String[] data) {
|
||||
if (data.length > 0 && !data[0].isEmpty()) {
|
||||
char possibleMarker = data[0].charAt(0);
|
||||
if (possibleMarker == UtfEncodingKt.UTF8_MODE_MARKER) {
|
||||
return UtfEncodingKt.stringsToBytes(dropMarker(data));
|
||||
}
|
||||
if (possibleMarker == _8TO7_MODE_MARKER) {
|
||||
data = dropMarker(data);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] bytes = combineStringArrayIntoBytes(data);
|
||||
// Adding 0x7f modulo max byte value is equivalent to subtracting 1 the same modulo, which is inverse to what happens in encodeBytes
|
||||
addModuloByte(bytes, 0x7f);
|
||||
return decode7to8(bytes);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String[] dropMarker(@NotNull String[] data) {
|
||||
// Clone because the clients should be able to use the passed array for their own purposes.
|
||||
// This is cheap because the size of the array is 1 or 2 almost always.
|
||||
String[] result = data.clone();
|
||||
result[0] = result[0].substring(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines the array of strings resulted from encodeBytes() into one long byte array
|
||||
*/
|
||||
@NotNull
|
||||
private static byte[] combineStringArrayIntoBytes(@NotNull String[] data) {
|
||||
int resultLength = 0;
|
||||
for (String s : data) {
|
||||
assert s.length() <= MAX_UTF8_INFO_LENGTH : "String is too long: " + s.length();
|
||||
resultLength += s.length();
|
||||
}
|
||||
|
||||
byte[] result = new byte[resultLength];
|
||||
int p = 0;
|
||||
for (String s : data) {
|
||||
for (int i = 0, n = s.length(); i < n; i++) {
|
||||
result[p++] = (byte) s.charAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the byte array resulted from encode8to7().
|
||||
*
|
||||
* Each byte of the input array has at most 7 valuable bits of information. So the decoding is equivalent to the following: least
|
||||
* significant 7 bits of all input bytes are combined into one long bit string. This bit string is then split into groups of 8 bits,
|
||||
* each of which forms a byte in the output. If there are any leftovers, they are ignored, since they were added just as a padding and
|
||||
* do not comprise a full byte.
|
||||
*
|
||||
* Suppose the following encoded byte array is given (bits are numbered the same way as in encode8to7() doc):
|
||||
*
|
||||
* 01234567 01234567 01234567 01234567
|
||||
*
|
||||
* The output of the following form would be produced:
|
||||
*
|
||||
* 01234560 12345601 23456012
|
||||
*
|
||||
* Note how all most significant bits and leftovers are dropped, since they don't contain any useful information
|
||||
*/
|
||||
@NotNull
|
||||
private static byte[] decode7to8(@NotNull byte[] data) {
|
||||
// floor(7 * data.length / 8)
|
||||
int resultLength = 7 * data.length / 8;
|
||||
|
||||
byte[] result = new byte[resultLength];
|
||||
|
||||
// We maintain a pointer to an input bit in the same fashion as in encode8to7(): it's represented as two numbers: index of the
|
||||
// current byte in the input and index of the bit in the byte
|
||||
int byteIndex = 0;
|
||||
int bit = 0;
|
||||
|
||||
// A resulting byte is comprised of 8 bits, starting from the current bit. Since each input byte only "contains 7 bytes", a
|
||||
// resulting byte always consists of two parts: several most significant bits of the current byte and several least significant bits
|
||||
// of the next byte
|
||||
for (int i = 0; i < resultLength; i++) {
|
||||
int firstPart = (data[byteIndex] & 0xff) >>> bit;
|
||||
byteIndex++;
|
||||
int secondPart = (data[byteIndex] & ((1 << (bit + 1)) - 1)) << 7 - bit;
|
||||
result[i] = (byte) (firstPart + secondPart);
|
||||
|
||||
if (bit == 6) {
|
||||
byteIndex++;
|
||||
bit = 0;
|
||||
}
|
||||
else {
|
||||
bit++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.serialization.jvm
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
|
||||
// The purpose of this class is to map Kotlin classes to JVM bytecode desc strings, as KotlinTypeMapper does in the backend.
|
||||
// It's used as an optimization during serialization/deserialization: if there's no JVM signature for a method/property/constructor,
|
||||
// it means that the JVM signature should be trivially computable from the Kotlin signature with this class.
|
||||
// It's not required to support everything in KotlinTypeMapper, but the more it does, the more we save on JVM signatures in proto metadata.
|
||||
// Note that improving the behavior of this class may break binary compatibility of code compiled by Kotlin, because it may make
|
||||
// the new compiler skip writing the signatures it now thinks are trivial, and the old compiler would recreate them incorrectly.
|
||||
object ClassMapperLite {
|
||||
@JvmStatic
|
||||
fun mapClass(classId: ClassId): String {
|
||||
val internalName = classId.asString().replace('.', '$')
|
||||
val simpleName = internalName.removePrefix("kotlin/")
|
||||
if (simpleName != internalName) {
|
||||
for (jvmPrimitive in JvmPrimitiveType.values()) {
|
||||
val primitiveType = jvmPrimitive.primitiveType
|
||||
if (simpleName == primitiveType.typeName.asString()) return jvmPrimitive.desc
|
||||
if (simpleName == primitiveType.arrayTypeName.asString()) return "[" + jvmPrimitive.desc
|
||||
}
|
||||
|
||||
if (simpleName == KotlinBuiltIns.FQ_NAMES.unit.shortName().asString()) return "V"
|
||||
}
|
||||
|
||||
val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(classId.asSingleFqName().toUnsafe())
|
||||
if (javaClassId != null) {
|
||||
return "L" + javaClassId.asString().replace('.', '$') + ";"
|
||||
}
|
||||
|
||||
return "L$internalName;"
|
||||
}
|
||||
}
|
||||
+2914
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.serialization.jvm
|
||||
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmNameResolver
|
||||
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
|
||||
import org.jetbrains.kotlin.serialization.ClassData
|
||||
import org.jetbrains.kotlin.serialization.PackageData
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.*
|
||||
import java.io.ByteArrayInputStream
|
||||
|
||||
object JvmProtoBufUtil {
|
||||
val EXTENSION_REGISTRY: ExtensionRegistryLite = run {
|
||||
val registry = ExtensionRegistryLite.newInstance()
|
||||
JvmProtoBuf.registerAllExtensions(registry)
|
||||
registry
|
||||
}
|
||||
|
||||
@JvmStatic fun readClassDataFrom(data: Array<String>, strings: Array<String>): ClassData =
|
||||
readClassDataFrom(BitEncoding.decodeBytes(data), strings)
|
||||
|
||||
@JvmStatic fun readClassDataFrom(bytes: ByteArray, strings: Array<String>): ClassData {
|
||||
val input = ByteArrayInputStream(bytes)
|
||||
val nameResolver = JvmNameResolver(JvmProtoBuf.StringTableTypes.parseDelimitedFrom(input, EXTENSION_REGISTRY), strings)
|
||||
val classProto = ProtoBuf.Class.parseFrom(input, EXTENSION_REGISTRY)
|
||||
return ClassData(nameResolver, classProto)
|
||||
}
|
||||
|
||||
@JvmStatic fun readPackageDataFrom(data: Array<String>, strings: Array<String>): PackageData =
|
||||
readPackageDataFrom(BitEncoding.decodeBytes(data), strings)
|
||||
|
||||
@JvmStatic fun readPackageDataFrom(bytes: ByteArray, strings: Array<String>): PackageData {
|
||||
val input = ByteArrayInputStream(bytes)
|
||||
val nameResolver = JvmNameResolver(JvmProtoBuf.StringTableTypes.parseDelimitedFrom(input, EXTENSION_REGISTRY), strings)
|
||||
val packageProto = ProtoBuf.Package.parseFrom(input, EXTENSION_REGISTRY)
|
||||
return PackageData(nameResolver, packageProto)
|
||||
}
|
||||
|
||||
// returns JVM signature in the format: "equals(Ljava/lang/Object;)Z"
|
||||
fun getJvmMethodSignature(
|
||||
proto: ProtoBuf.Function,
|
||||
nameResolver: NameResolver,
|
||||
typeTable: TypeTable
|
||||
): String? {
|
||||
val signature =
|
||||
if (proto.hasExtension(JvmProtoBuf.methodSignature)) proto.getExtension(JvmProtoBuf.methodSignature) else null
|
||||
val name = if (signature != null && signature.hasName()) signature.name else proto.name
|
||||
val desc = if (signature != null && signature.hasDesc()) {
|
||||
nameResolver.getString(signature.desc)
|
||||
}
|
||||
else {
|
||||
val parameterTypes = listOfNotNull(proto.receiverType(typeTable)) + proto.valueParameterList.map { it.type(typeTable) }
|
||||
|
||||
val parametersDesc = parameterTypes.map { mapTypeDefault(it, nameResolver) ?: return null }
|
||||
val returnTypeDesc = mapTypeDefault(proto.returnType(typeTable), nameResolver) ?: return null
|
||||
|
||||
parametersDesc.joinToString(separator = "", prefix = "(", postfix = ")") + returnTypeDesc
|
||||
}
|
||||
return nameResolver.getString(name) + desc
|
||||
}
|
||||
|
||||
fun getJvmConstructorSignature(
|
||||
proto: ProtoBuf.Constructor,
|
||||
nameResolver: NameResolver,
|
||||
typeTable: TypeTable
|
||||
): String? {
|
||||
val signature =
|
||||
if (proto.hasExtension(JvmProtoBuf.constructorSignature)) proto.getExtension(JvmProtoBuf.constructorSignature) else null
|
||||
val desc = if (signature != null && signature.hasDesc()) {
|
||||
nameResolver.getString(signature.desc)
|
||||
}
|
||||
else {
|
||||
proto.valueParameterList.map {
|
||||
mapTypeDefault(it.type(typeTable), nameResolver) ?: return null
|
||||
}.joinToString(separator = "", prefix = "(", postfix = ")V")
|
||||
}
|
||||
return "<init>" + desc
|
||||
}
|
||||
|
||||
fun getJvmFieldSignature(
|
||||
proto: ProtoBuf.Property,
|
||||
nameResolver: NameResolver,
|
||||
typeTable: TypeTable
|
||||
): PropertySignature? {
|
||||
val signature =
|
||||
if (proto.hasExtension(JvmProtoBuf.propertySignature)) proto.getExtension(JvmProtoBuf.propertySignature) else return null
|
||||
val field =
|
||||
if (signature.hasField()) signature.field else null
|
||||
|
||||
val name = if (field != null && field.hasName()) field.name else proto.name
|
||||
val desc =
|
||||
if (field != null && field.hasDesc()) nameResolver.getString(field.desc)
|
||||
else mapTypeDefault(proto.returnType(typeTable), nameResolver) ?: return null
|
||||
|
||||
return PropertySignature(nameResolver.getString(name), desc)
|
||||
}
|
||||
|
||||
data class PropertySignature(val name: String, val desc: String)
|
||||
|
||||
private fun mapTypeDefault(type: ProtoBuf.Type, nameResolver: NameResolver): String? {
|
||||
return if (type.hasClassName()) ClassMapperLite.mapClass(nameResolver.getClassId(type.className)) else null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.serialization.jvm
|
||||
|
||||
import java.util.*
|
||||
|
||||
// The maximum possible length of the byte array in the CONSTANT_Utf8_info structure in the bytecode, as per JVMS7 4.4.7
|
||||
const val MAX_UTF8_INFO_LENGTH = 65535
|
||||
|
||||
const val UTF8_MODE_MARKER = 0.toChar()
|
||||
|
||||
fun bytesToStrings(bytes: ByteArray): Array<String> {
|
||||
val result = ArrayList<String>(1)
|
||||
val buffer = StringBuilder()
|
||||
var bytesInBuffer = 0
|
||||
|
||||
buffer.append(UTF8_MODE_MARKER)
|
||||
// Zeros effectively occupy two bytes because each 0x0 is converted to 0x80 0xc0 in Modified UTF-8, see JVMS7 4.4.7
|
||||
bytesInBuffer += 2
|
||||
|
||||
for (b in bytes) {
|
||||
val c = b.toInt() and 0xFF // 0 <= c <= 255
|
||||
buffer.append(c.toChar())
|
||||
if (0 < b && b <= 127) {
|
||||
bytesInBuffer++
|
||||
}
|
||||
else {
|
||||
bytesInBuffer += 2
|
||||
}
|
||||
|
||||
if (bytesInBuffer >= MAX_UTF8_INFO_LENGTH - 1) {
|
||||
result.add(buffer.toString())
|
||||
buffer.setLength(0)
|
||||
bytesInBuffer = 0
|
||||
}
|
||||
}
|
||||
|
||||
if (!buffer.isEmpty()) {
|
||||
result.add(buffer.toString())
|
||||
}
|
||||
|
||||
return result.toTypedArray()
|
||||
}
|
||||
|
||||
fun stringsToBytes(strings: Array<String>): ByteArray {
|
||||
val resultLength = strings.sumBy { it.length }
|
||||
val result = ByteArray(resultLength)
|
||||
|
||||
var i = 0
|
||||
for (s in strings) {
|
||||
for (si in 0..s.length - 1) {
|
||||
result[i++] = s[si].toByte()
|
||||
}
|
||||
}
|
||||
|
||||
assert(i == result.size) { "Should have reached the end" }
|
||||
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user