Introduce optimized BuiltInAnnotationDescriptor for built-in annotations

It's built on a FQ name and avoids resolution of the annotation class
descriptor as much as possible
This commit is contained in:
Alexander Udalov
2017-07-04 17:22:33 +03:00
parent f39106f75c
commit 541b9dab52
6 changed files with 61 additions and 41 deletions
@@ -19,12 +19,14 @@ package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl 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.descriptors.annotations.composeAnnotations
import org.jetbrains.kotlin.descriptors.annotations.createUnsafeVarianceAnnotation
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
internal class UnsafeVarianceTypeSubstitution(kotlinBuiltIns: KotlinBuiltIns) : TypeSubstitution() { internal class UnsafeVarianceTypeSubstitution(builtIns: KotlinBuiltIns) : TypeSubstitution() {
private val unsafeVarianceAnnotations = AnnotationsImpl(listOf(kotlinBuiltIns.createUnsafeVarianceAnnotation())) private val unsafeVarianceAnnotations = AnnotationsImpl(listOf(
BuiltInAnnotationDescriptor(builtIns, KotlinBuiltIns.FQ_NAMES.unsafeVariance, emptyMap())
))
override fun get(key: KotlinType) = null override fun get(key: KotlinType) = null
@@ -563,11 +563,6 @@ public abstract class KotlinBuiltIns {
return getBuiltInClassByName("Throwable"); return getBuiltInClassByName("Throwable");
} }
@NotNull
public ClassDescriptor getDeprecatedAnnotation() {
return getBuiltInClassByName(FQ_NAMES.deprecated.shortName());
}
@Nullable @Nullable
private static ClassDescriptor getEnumEntry(@NotNull ClassDescriptor enumDescriptor, @NotNull String entryName) { private static ClassDescriptor getEnumEntry(@NotNull ClassDescriptor enumDescriptor, @NotNull String entryName) {
ClassifierDescriptor result = enumDescriptor.getUnsubstitutedInnerClassesScope().getContributedClassifier( ClassifierDescriptor result = enumDescriptor.getUnsubstitutedInnerClassesScope().getContributedClassifier(
@@ -20,10 +20,9 @@ import org.jetbrains.kotlin.builtins.functions.BuiltInFictitiousFunctionClassFac
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
import org.jetbrains.kotlin.descriptors.annotations.BuiltInAnnotationDescriptor
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -164,12 +163,10 @@ fun getFunctionTypeArgumentProjections(
parameterTypes.mapIndexedTo(arguments) { index, type -> parameterTypes.mapIndexedTo(arguments) { index, type ->
val name = parameterNames?.get(index)?.takeUnless { it.isSpecial } val name = parameterNames?.get(index)?.takeUnless { it.isSpecial }
val typeToUse = if (name != null) { val typeToUse = if (name != null) {
val annotationClass = builtIns.getBuiltInClassByName(KotlinBuiltIns.FQ_NAMES.parameterName.shortName()) val parameterNameAnnotation = BuiltInAnnotationDescriptor(
val nameValue = ConstantValueFactory(builtIns).createStringValue(name.asString()) builtIns,
val parameterNameAnnotation = AnnotationDescriptorImpl( KotlinBuiltIns.FQ_NAMES.parameterName,
annotationClass.defaultType, mapOf(Name.identifier("name") to ConstantValueFactory(builtIns).createStringValue(name.asString()))
mapOf(Name.identifier("name") to nameValue),
SourceElement.NO_SOURCE
) )
type.replaceAnnotations(AnnotationsImpl(type.annotations + parameterNameAnnotation)) type.replaceAnnotations(AnnotationsImpl(type.annotations + parameterNameAnnotation))
} }
@@ -199,18 +196,14 @@ fun createFunctionType(
val parameterCount = if (receiverType == null) size else size + 1 val parameterCount = if (receiverType == null) size else size + 1
val classDescriptor = if (suspendFunction) builtIns.getSuspendFunction(parameterCount) else builtIns.getFunction(parameterCount) val classDescriptor = if (suspendFunction) builtIns.getSuspendFunction(parameterCount) else builtIns.getFunction(parameterCount)
// TODO: preserve laziness of given annotations
val typeAnnotations = val typeAnnotations =
if (receiverType == null || annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType) != null) { if (receiverType == null || annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType) != null) {
annotations annotations
} }
else { else {
val extensionFunctionAnnotation = AnnotationDescriptorImpl( AnnotationsImpl(annotations +
builtIns.getBuiltInClassByName(KotlinBuiltIns.FQ_NAMES.extensionFunctionType.shortName()).defaultType, BuiltInAnnotationDescriptor(builtIns, KotlinBuiltIns.FQ_NAMES.extensionFunctionType, emptyMap()))
emptyMap(), SourceElement.NO_SOURCE
)
// TODO: preserve laziness of given annotations
AnnotationsImpl(annotations + extensionFunctionAnnotation)
} }
return KotlinTypeFactory.simpleNotNullType(typeAnnotations, classDescriptor, arguments) return KotlinTypeFactory.simpleNotNullType(typeAnnotations, classDescriptor, arguments)
@@ -0,0 +1,38 @@
/*
* 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.descriptors.annotations
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.types.KotlinType
import kotlin.LazyThreadSafetyMode.PUBLICATION
class BuiltInAnnotationDescriptor(
private val builtIns: KotlinBuiltIns,
override val fqName: FqName,
override val allValueArguments: Map<Name, ConstantValue<*>>
) : AnnotationDescriptor {
override val type: KotlinType by lazy(PUBLICATION) {
builtIns.getBuiltInClassByFqName(fqName).defaultType
}
override val source: SourceElement
get() = SourceElement.NO_SOURCE
}
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.MemberDescriptor import org.jetbrains.kotlin.descriptors.MemberDescriptor
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -36,23 +35,23 @@ fun KotlinBuiltIns.createDeprecatedAnnotation(
replaceWith: String = "", replaceWith: String = "",
level: String = "WARNING" level: String = "WARNING"
): AnnotationDescriptor { ): AnnotationDescriptor {
val replaceWithAnnotation = AnnotationDescriptorImpl( val replaceWithAnnotation = BuiltInAnnotationDescriptor(
getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.replaceWith).defaultType, this,
KotlinBuiltIns.FQ_NAMES.replaceWith,
mapOf( mapOf(
REPLACE_WITH_EXPRESSION_NAME to StringValue(replaceWith, this), REPLACE_WITH_EXPRESSION_NAME to StringValue(replaceWith, this),
REPLACE_WITH_IMPORTS_NAME to ArrayValue(emptyList(), getArrayType(Variance.INVARIANT, stringType), this) REPLACE_WITH_IMPORTS_NAME to ArrayValue(emptyList(), getArrayType(Variance.INVARIANT, stringType), this)
), )
SourceElement.NO_SOURCE
) )
return AnnotationDescriptorImpl( return BuiltInAnnotationDescriptor(
deprecatedAnnotation.defaultType, this,
KotlinBuiltIns.FQ_NAMES.deprecated,
mapOf( mapOf(
DEPRECATED_MESSAGE_NAME to StringValue(message, this), DEPRECATED_MESSAGE_NAME to StringValue(message, this),
DEPRECATED_REPLACE_WITH_NAME to AnnotationValue(replaceWithAnnotation), DEPRECATED_REPLACE_WITH_NAME to AnnotationValue(replaceWithAnnotation),
DEPRECATED_LEVEL_NAME to EnumValue(getDeprecationLevelEnumEntry(level) ?: error("Deprecation level $level not found")) DEPRECATED_LEVEL_NAME to EnumValue(getDeprecationLevelEnumEntry(level) ?: error("Deprecation level $level not found"))
), )
SourceElement.NO_SOURCE
) )
} }
@@ -62,11 +61,6 @@ private val DEPRECATED_LEVEL_NAME = Name.identifier("level")
private val REPLACE_WITH_EXPRESSION_NAME = Name.identifier("expression") private val REPLACE_WITH_EXPRESSION_NAME = Name.identifier("expression")
private val REPLACE_WITH_IMPORTS_NAME = Name.identifier("imports") private val REPLACE_WITH_IMPORTS_NAME = Name.identifier("imports")
fun KotlinBuiltIns.createUnsafeVarianceAnnotation(): AnnotationDescriptor {
val unsafeVarianceAnnotation = getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.unsafeVariance)
return AnnotationDescriptorImpl(unsafeVarianceAnnotation.defaultType, emptyMap(), SourceElement.NO_SOURCE)
}
private val INLINE_ONLY_ANNOTATION_FQ_NAME = FqName("kotlin.internal.InlineOnly") private val INLINE_ONLY_ANNOTATION_FQ_NAME = FqName("kotlin.internal.InlineOnly")
fun MemberDescriptor.isInlineOnlyOrReifiable(): Boolean = fun MemberDescriptor.isInlineOnlyOrReifiable(): Boolean =
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.quickfix.replaceWith
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
@@ -37,12 +38,10 @@ import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.annotations.argumentValue import org.jetbrains.kotlin.resolve.annotations.argumentValue
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -73,8 +72,7 @@ abstract class DeprecatedSymbolUsageFixBase(
companion object { companion object {
fun fetchReplaceWithPattern(descriptor: DeclarationDescriptor, project: Project): ReplaceWith? { fun fetchReplaceWithPattern(descriptor: DeclarationDescriptor, project: Project): ReplaceWith? {
val annotationClass = descriptor.builtIns.deprecatedAnnotation val annotation = descriptor.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.deprecated) ?: return null
val annotation = descriptor.annotations.findAnnotation(DescriptorUtils.getFqNameSafe(annotationClass)) ?: return null
val replaceWithValue = annotation.argumentValue(kotlin.Deprecated::replaceWith.name) as? AnnotationDescriptor ?: return null val replaceWithValue = annotation.argumentValue(kotlin.Deprecated::replaceWith.name) as? AnnotationDescriptor ?: return null
val pattern = replaceWithValue.argumentValue(kotlin.ReplaceWith::expression.name) as? String ?: return null val pattern = replaceWithValue.argumentValue(kotlin.ReplaceWith::expression.name) as? String ?: return null
if (pattern.isEmpty()) return null if (pattern.isEmpty()) return null