/
KtFirSymbolInfoProvider.kt
161 lines (136 loc) · 7.64 KB
/
KtFirSymbolInfoProvider.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.api.fir.components
import org.jetbrains.kotlin.analysis.api.components.KtSymbolInfoProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.getJvmNameFromAnnotation
import org.jetbrains.kotlin.analysis.api.fir.symbols.*
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.api.symbols.KtClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtReceiverParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.JvmStandardClassIds
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
import org.jetbrains.kotlin.resolve.deprecation.SimpleDeprecationInfo
internal class KtFirSymbolInfoProvider(
override val analysisSession: KtFirAnalysisSession,
override val token: KtLifetimeToken
) : KtSymbolInfoProvider(), KtFirAnalysisSessionComponent {
private val apiVersion = analysisSession.useSiteSession.languageVersionSettings.apiVersion
override fun getDeprecation(symbol: KtSymbol): DeprecationInfo? {
if (symbol is KtFirPackageSymbol || symbol is KtReceiverParameterSymbol) return null
require(symbol is KtFirSymbol<*>) { "${this::class}" }
// Optimization: Avoid building `firSymbol` of `KtFirPsiJavaClassSymbol` if it definitely isn't deprecated.
if (symbol is KtFirPsiJavaClassSymbol && !symbol.mayHaveDeprecation()) {
return null
}
return when (val firSymbol = symbol.firSymbol) {
is FirPropertySymbol -> {
firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession, AnnotationUseSiteTarget.PROPERTY)
}
is FirBackingFieldSymbol -> {
firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession, AnnotationUseSiteTarget.FIELD)
}
else -> {
firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession)
}
}?.toDeprecationInfo()
}
private fun KtFirPsiJavaClassSymbol.mayHaveDeprecation(): Boolean {
if (!hasAnnotations) return false
// Check the simple names of the Java annotations. While presence of such an annotation name does not prove deprecation, it is a
// necessary condition for it. Type aliases are not a problem here: Java code cannot access Kotlin type aliases. (Currently,
// deprecation annotation type aliases do not work in Kotlin, either, but this might change in the future.)
val deprecationAnnotationSimpleNames = analysisSession.useSiteSession.annotationPlatformSupport.deprecationAnnotationsSimpleNames
return annotationSimpleNames.any { it != null && it in deprecationAnnotationSimpleNames }
}
override fun getDeprecation(symbol: KtSymbol, annotationUseSiteTarget: AnnotationUseSiteTarget?): DeprecationInfo? {
require(symbol is KtFirSymbol<*>)
return if (annotationUseSiteTarget != null) {
symbol.firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession, annotationUseSiteTarget)
} else {
symbol.firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession)
}?.toDeprecationInfo()
}
override fun getGetterDeprecation(symbol: KtPropertySymbol): DeprecationInfo? {
require(symbol is KtFirSymbol<*>)
return symbol.firSymbol.getDeprecationForCallSite(
analysisSession.useSiteSession,
AnnotationUseSiteTarget.PROPERTY_GETTER,
AnnotationUseSiteTarget.PROPERTY,
)?.toDeprecationInfo()
}
override fun getSetterDeprecation(symbol: KtPropertySymbol): DeprecationInfo? {
require(symbol is KtFirSymbol<*>)
return symbol.firSymbol.getDeprecationForCallSite(
analysisSession.useSiteSession,
AnnotationUseSiteTarget.PROPERTY_SETTER,
AnnotationUseSiteTarget.PROPERTY,
)?.toDeprecationInfo()
}
private fun FirDeprecationInfo.toDeprecationInfo(): DeprecationInfo {
// We pass null as the message, otherwise we can trigger a contract violation
// as getMessage will call lazyResolveToPhase(ANNOTATION_ARGUMENTS)
// TODO(KT-67823) stop exposing compiler internals, as the message isn't actually required by the callers.
return SimpleDeprecationInfo(deprecationLevel, propagatesToOverrides, null)
}
override fun getJavaGetterName(symbol: KtPropertySymbol): Name {
require(symbol is KtFirSymbol<*>)
if (symbol is KtFirSyntheticJavaPropertySymbol) {
return symbol.javaGetterSymbol.name
}
val firProperty = symbol.firSymbol.fir
requireIsInstance<FirProperty>(firProperty)
return getJvmName(firProperty, isSetter = false)
}
override fun getJavaSetterName(symbol: KtPropertySymbol): Name? {
require(symbol is KtFirSymbol<*>)
if (symbol is KtFirSyntheticJavaPropertySymbol) {
return symbol.javaSetterSymbol?.name
}
val firProperty = symbol.firSymbol.fir
requireIsInstance<FirProperty>(firProperty)
if (firProperty.isVal) return null
return getJvmName(firProperty, isSetter = true)
}
override fun getAnnotationApplicableTargets(symbol: KtClassOrObjectSymbol): Set<KotlinTarget>? {
requireIsInstance<KtFirSymbol<*>>(symbol)
if (symbol !is KtFirNamedClassOrObjectSymbolBase) return null
if (symbol.firSymbol.classKind != ClassKind.ANNOTATION_CLASS) return null
return symbol.firSymbol.getAllowedAnnotationTargets(analysisSession.useSiteSession)
}
private fun getJvmName(property: FirProperty, isSetter: Boolean): Name {
if (property.backingField?.symbol?.hasAnnotation(JvmStandardClassIds.Annotations.JvmField, analysisSession.useSiteSession) == true) {
return property.name
}
return Name.identifier(getJvmNameAsString(property, isSetter))
}
private fun getJvmNameAsString(property: FirProperty, isSetter: Boolean): String {
val useSiteTarget = if (isSetter) AnnotationUseSiteTarget.PROPERTY_SETTER else AnnotationUseSiteTarget.PROPERTY_GETTER
val jvmNameFromProperty = property.getJvmNameFromAnnotation(analysisSession.useSiteSession, useSiteTarget)
if (jvmNameFromProperty != null) {
return jvmNameFromProperty
}
val accessor = if (isSetter) property.setter else property.getter
val jvmNameFromAccessor = accessor?.getJvmNameFromAnnotation(analysisSession.useSiteSession)
if (jvmNameFromAccessor != null) {
return jvmNameFromAccessor
}
val identifier = property.name.identifier
return if (isSetter) JvmAbi.setterName(identifier) else JvmAbi.getterName(identifier)
}
}