SLC: implement PsiMethod#getThrowsList

This commit is contained in:
Jinseong Jeon
2022-12-01 22:33:09 -08:00
committed by Space Team
parent 42a0acac4f
commit cc7083d59e
6 changed files with 111 additions and 19 deletions
@@ -9,18 +9,21 @@ import com.intellij.psi.CommonClassNames.JAVA_LANG_ANNOTATION_RETENTION
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiModifierList
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiElement
import com.intellij.psi.impl.light.LightReferenceListBuilder
import org.jetbrains.annotations.NotNull
import org.jetbrains.annotations.Nullable
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.annotations.KtConstantAnnotationValue
import org.jetbrains.kotlin.analysis.api.annotations.KtEnumEntryAnnotationValue
import org.jetbrains.kotlin.analysis.api.annotations.KtNamedAnnotationValue
import org.jetbrains.kotlin.analysis.api.annotations.annotations
import org.jetbrains.kotlin.analysis.api.annotations.*
import org.jetbrains.kotlin.analysis.api.components.buildClassType
import org.jetbrains.kotlin.analysis.api.symbols.KtFileSymbol
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtAnnotatedSymbol
import org.jetbrains.kotlin.analysis.api.types.KtTypeMappingMode
import org.jetbrains.kotlin.builtins.StandardNames.DEFAULT_VALUE_PARAMETER
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.light.classes.symbol.NullabilityType
import org.jetbrains.kotlin.light.classes.symbol.classes.SymbolLightClassBase
import org.jetbrains.kotlin.light.classes.symbol.methods.SymbolLightMethod
import org.jetbrains.kotlin.load.java.JvmAbi.JVM_FIELD_ANNOTATION_CLASS_ID
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.RETENTION_POLICY_ENUM
@@ -30,6 +33,7 @@ import org.jetbrains.kotlin.name.JvmNames.JVM_NAME_CLASS_ID
import org.jetbrains.kotlin.name.JvmNames.JVM_OVERLOADS_CLASS_ID
import org.jetbrains.kotlin.name.JvmNames.JVM_SYNTHETIC_ANNOTATION_CLASS_ID
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_CLASS_ID
import org.jetbrains.kotlin.resolve.annotations.JVM_THROWS_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue
import org.jetbrains.kotlin.resolve.inline.INLINE_ONLY_ANNOTATION_FQ_NAME
@@ -92,19 +96,33 @@ internal fun KtAnnotatedSymbol.hasAnnotation(
classId: ClassId,
annotationUseSiteTarget: AnnotationUseSiteTarget?,
strictUseSite: Boolean = true,
): Boolean = annotations.any {
val useSiteTarget = it.useSiteTarget
(useSiteTarget == annotationUseSiteTarget || !strictUseSite && useSiteTarget == null) && it.classId == classId
}
): Boolean = findAnnotation(classId, annotationUseSiteTarget, strictUseSite) != null
internal fun KtAnnotatedSymbol.findAnnotation(
classId: ClassId,
annotationUseSiteTarget: AnnotationUseSiteTarget?,
strictUseSite: Boolean = true,
): KtAnnotationApplication? =
annotations.find {
val useSiteTarget = it.useSiteTarget
(useSiteTarget == annotationUseSiteTarget || !strictUseSite && useSiteTarget == null) && it.classId == classId
}
internal fun KtAnnotatedSymbol.hasAnnotation(
fqName: FqName,
annotationUseSiteTarget: AnnotationUseSiteTarget?,
strictUseSite: Boolean = true,
): Boolean = annotations.any {
val useSiteTarget = it.useSiteTarget
(useSiteTarget == annotationUseSiteTarget || !strictUseSite && useSiteTarget == null) && it.classId?.asSingleFqName() == fqName
}
): Boolean = findAnnotation(fqName, annotationUseSiteTarget, strictUseSite) != null
internal fun KtAnnotatedSymbol.findAnnotation(
fqName: FqName,
annotationUseSiteTarget: AnnotationUseSiteTarget?,
strictUseSite: Boolean = true,
): KtAnnotationApplication? =
annotations.find {
val useSiteTarget = it.useSiteTarget
(useSiteTarget == annotationUseSiteTarget || !strictUseSite && useSiteTarget == null) && it.classId?.asSingleFqName() == fqName
}
internal fun NullabilityType.computeNullabilityAnnotation(parent: PsiModifierList): SymbolLightSimpleAnnotation? {
return when (this) {
@@ -192,3 +210,33 @@ private fun createRetentionRuntimeAnnotation(modifierList: PsiModifierList, rete
)
)
)
context(KtAnalysisSession)
internal fun KtAnnotatedSymbol.computeThrowsList(
builder: LightReferenceListBuilder,
annotationUseSiteTarget: AnnotationUseSiteTarget?,
useSitePosition: PsiElement,
containingClass: SymbolLightClassBase,
strictUseSite: Boolean = true,
) {
val annoApp = findAnnotation(JVM_THROWS_ANNOTATION_FQ_NAME, annotationUseSiteTarget, strictUseSite) ?: return
fun handleAnnotationValue(annotationValue: KtAnnotationValue) = when (annotationValue) {
is KtArrayAnnotationValue -> {
annotationValue.values.forEach(::handleAnnotationValue)
}
is KtKClassAnnotationValue.KtNonLocalKClassAnnotationValue -> {
val psiType = buildClassType(annotationValue.classId).asPsiType(
useSitePosition,
KtTypeMappingMode.DEFAULT,
containingClass.isAnnotationType
)
(psiType as? PsiClassType)?.let {
builder.addReference(it)
}
}
else -> {}
}
annoApp.arguments.forEach { handleAnnotationValue(it.expression) }
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.light.classes.symbol.methods
import com.intellij.openapi.util.TextRange
import com.intellij.psi.*
import com.intellij.psi.impl.light.LightParameterListBuilder
import com.intellij.psi.impl.light.LightReferenceListBuilder
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.KtConstantInitializerValue
import org.jetbrains.kotlin.analysis.api.KtConstantValueForAnnotation
@@ -22,6 +23,7 @@ import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.light.classes.symbol.*
import org.jetbrains.kotlin.light.classes.symbol.annotations.*
import org.jetbrains.kotlin.light.classes.symbol.annotations.computeAnnotations
import org.jetbrains.kotlin.light.classes.symbol.annotations.getJvmNameFromAnnotation
import org.jetbrains.kotlin.light.classes.symbol.annotations.hasDeprecatedAnnotation
@@ -131,6 +133,18 @@ internal class SymbolLightAccessorMethod private constructor(
//TODO Fix it when SymbolConstructorValueParameter be ready
private val isParameter: Boolean get() = containingPropertyDeclaration == null || containingPropertyDeclaration is KtParameter
override fun computeThrowsList(builder: LightReferenceListBuilder) {
analyzeForLightClasses(ktModule) {
propertyAccessorSymbol().computeThrowsList(
builder,
accessorSite,
this@SymbolLightAccessorMethod,
containingClass,
strictUseSite = false
)
}
}
private fun computeAnnotations(modifierList: PsiModifierList): List<PsiAnnotation> = analyzeForLightClasses(ktModule) {
val nullabilityApplicable = isGetter &&
!modifierList.hasModifierProperty(PsiModifier.PRIVATE) &&
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.light.classes.symbol.methods
import com.intellij.psi.PsiIdentifier
import com.intellij.psi.PsiParameterList
import com.intellij.psi.impl.light.LightReferenceListBuilder
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
@@ -16,6 +17,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.sourcePsiSafe
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
import org.jetbrains.kotlin.light.classes.symbol.annotations.computeThrowsList
import org.jetbrains.kotlin.light.classes.symbol.annotations.hasDeprecatedAnnotation
import org.jetbrains.kotlin.light.classes.symbol.classes.SymbolLightClassBase
import org.jetbrains.kotlin.light.classes.symbol.compareSymbolPointers
@@ -120,6 +122,17 @@ internal abstract class SymbolLightMethod<FType : KtFunctionLikeSymbol> private
override fun getParameterList(): PsiParameterList = _parametersList
override fun computeThrowsList(builder: LightReferenceListBuilder) {
withFunctionSymbol { functionSymbol ->
functionSymbol.computeThrowsList(
builder,
annotationUseSiteTarget = null,
this@SymbolLightMethod,
containingClass
)
}
}
override fun isValid(): Boolean = super.isValid() && functionDeclaration?.isValid ?: functionSymbolPointer.isValid(ktModule)
override fun isOverride(): Boolean = withFunctionSymbol { it.getDirectlyOverriddenSymbols().isNotEmpty() }
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.light.classes.symbol.methods
import com.intellij.psi.*
import com.intellij.psi.impl.PsiImplUtil
import com.intellij.psi.impl.PsiSuperMethodImplUtil
import com.intellij.psi.impl.light.LightReferenceListBuilder
import com.intellij.psi.util.MethodSignature
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
@@ -19,6 +20,7 @@ import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.classes.KotlinLightReferenceListBuilder
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.classes.cannotModify
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.mangleInternalName
import org.jetbrains.kotlin.descriptors.Visibilities
@@ -79,8 +81,23 @@ internal abstract class SymbolLightMethodBase(
abstract override fun hasTypeParameters(): Boolean
abstract override fun getTypeParameterList(): PsiTypeParameterList?
override fun getThrowsList(): PsiReferenceList =
KotlinLightReferenceListBuilder(manager, language, PsiReferenceList.Role.THROWS_LIST) //TODO()
private class SymbolLightThrowsReferencesListBuilder(
private val parentMethod: PsiMethod
) : KotlinLightReferenceListBuilder(parentMethod.manager, parentMethod.language, PsiReferenceList.Role.THROWS_LIST) {
override fun getParent(): PsiElement = parentMethod
override fun getContainingFile(): PsiFile = parentMethod.containingFile
}
private val _throwsList by lazyPub {
val builder = SymbolLightThrowsReferencesListBuilder(this)
computeThrowsList(builder)
builder
}
protected open fun computeThrowsList(builder: LightReferenceListBuilder) {}
override fun getThrowsList(): PsiReferenceList = _throwsList
override fun getDefaultValue(): PsiAnnotationMemberValue? = null
@@ -6,13 +6,13 @@ public final class MyException /* MyException*/ extends java.lang.Exception {
public final class C /* C*/ {
@kotlin.jvm.Throws(exceptionClasses = {java.io.IOException.class, MyException.class})
@org.jetbrains.annotations.NotNull()
public final java.lang.String readFile(@org.jetbrains.annotations.NotNull() java.lang.String);// readFile(java.lang.String)
public final java.lang.String readFile(@org.jetbrains.annotations.NotNull() java.lang.String) throws java.io.IOException, MyException;// readFile(java.lang.String)
@kotlin.jvm.Throws(exceptionClasses = {java.lang.Exception.class})
public C(int);// .ctor(int)
public C(int) throws java.lang.Exception;// .ctor(int)
@kotlin.jvm.Throws(exceptionClasses = {java.lang.Throwable.class})
public final void baz();// baz()
public final void baz() throws java.lang.Throwable;// baz()
public C();// .ctor()
@@ -1,9 +1,9 @@
public final class ThrowsAnnotationKt /* ThrowsAnnotationKt*/ {
@kotlin.jvm.Throws(exceptionClasses = {java.io.IOException.class, MyException.class})
@org.jetbrains.annotations.NotNull()
public static final java.lang.String readFile(@org.jetbrains.annotations.NotNull() java.lang.String);// readFile(java.lang.String)
public static final java.lang.String readFile(@org.jetbrains.annotations.NotNull() java.lang.String) throws java.io.IOException, MyException;// readFile(java.lang.String)
@kotlin.jvm.Throws(exceptionClasses = {java.lang.Throwable.class})
public static final void baz();// baz()
public static final void baz() throws java.lang.Throwable;// baz()
}