[FIR] Split creating fir for java declarations to separate methods

This commit is contained in:
Dmitriy Novozhilov
2020-09-24 12:26:25 +03:00
parent 0d29d6d361
commit a0db510e49
@@ -7,12 +7,10 @@ package org.jetbrains.kotlin.fir.java
import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.* import org.jetbrains.kotlin.fir.declarations.builder.*
@@ -26,6 +24,7 @@ import org.jetbrains.kotlin.fir.resolve.providers.SymbolProviderCache
import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped
import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.load.java.JavaClassFinder import org.jetbrains.kotlin.load.java.JavaClassFinder
@@ -57,7 +56,8 @@ class JavaSymbolProvider(
private val scopeProvider = JavaScopeProvider(::wrapScopeWithJvmMapped, this) private val scopeProvider = JavaScopeProvider(::wrapScopeWithJvmMapped, this)
private val facade: KotlinJavaPsiFacade get() = KotlinJavaPsiFacade.getInstance(project) private val facade: KotlinJavaPsiFacade get() = KotlinJavaPsiFacade.getInstance(project)
private val parentClassTypeParameterStackCache: SymbolProviderCache<FirRegularClassSymbol, JavaTypeParameterStack> = SymbolProviderCache() private val parentClassTypeParameterStackCache: SymbolProviderCache<FirRegularClassSymbol, JavaTypeParameterStack> =
SymbolProviderCache()
private fun findClass( private fun findClass(
classId: ClassId, classId: ClassId,
@@ -65,7 +65,8 @@ class JavaSymbolProvider(
): JavaClass? = facade.findClass(JavaClassFinder.Request(classId, previouslyFoundClassFileContent = content?.content), searchScope) ): JavaClass? = facade.findClass(JavaClassFinder.Request(classId, previouslyFoundClassFileContent = content?.content), searchScope)
@FirSymbolProviderInternals @FirSymbolProviderInternals
override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {} override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
}
private fun JavaTypeParameter.toFirTypeParameterSymbol( private fun JavaTypeParameter.toFirTypeParameterSymbol(
javaTypeParameterStack: JavaTypeParameterStack javaTypeParameterStack: JavaTypeParameterStack
@@ -140,7 +141,18 @@ class JavaSymbolProvider(
} }
}, },
) { firSymbol, foundClass -> ) { firSymbol, foundClass ->
foundClass?.let { javaClass -> convertJavaClassToFir(firSymbol, foundClass)
}
}
private class ValueParametersForAnnotationConstructor {
val valueParameters: MutableList<FirJavaValueParameter> = mutableListOf()
var valueParameterForValue: FirJavaValueParameter? = null
}
private fun convertJavaClassToFir(classSymbol: FirRegularClassSymbol, javaClass: JavaClass?): FirJavaClass? {
if (javaClass == null) return null
val classId = classSymbol.classId
val javaTypeParameterStack = JavaTypeParameterStack() val javaTypeParameterStack = JavaTypeParameterStack()
val outerClassId = classId.outerClassId val outerClassId = classId.outerClassId
val parentClassSymbol = if (outerClassId != null) { val parentClassSymbol = if (outerClassId != null) {
@@ -156,7 +168,7 @@ class JavaSymbolProvider(
val firJavaClass = buildJavaClass { val firJavaClass = buildJavaClass {
source = (javaClass as? JavaElementImpl<*>)?.psi?.toFirPsiSourceElement() source = (javaClass as? JavaElementImpl<*>)?.psi?.toFirPsiSourceElement()
session = this@JavaSymbolProvider.session session = this@JavaSymbolProvider.session
symbol = firSymbol symbol = classSymbol
name = javaClass.name name = javaClass.name
visibility = javaClass.visibility visibility = javaClass.visibility
modality = javaClass.modality modality = javaClass.modality
@@ -164,10 +176,10 @@ class JavaSymbolProvider(
this.isTopLevel = outerClassId == null this.isTopLevel = outerClassId == null
isStatic = javaClass.isStatic isStatic = javaClass.isStatic
this.javaTypeParameterStack = javaTypeParameterStack this.javaTypeParameterStack = javaTypeParameterStack
parentClassTypeParameterStackCache[firSymbol] = javaTypeParameterStack parentClassTypeParameterStackCache[classSymbol] = javaTypeParameterStack
existingNestedClassifierNames += javaClass.innerClassNames existingNestedClassifierNames += javaClass.innerClassNames
scopeProvider = this@JavaSymbolProvider.scopeProvider scopeProvider = this@JavaSymbolProvider.scopeProvider
val classTypeParameters = foundClass.typeParameters.convertTypeParameters(javaTypeParameterStack) val classTypeParameters = javaClass.typeParameters.convertTypeParameters(javaTypeParameterStack)
typeParameters += classTypeParameters typeParameters += classTypeParameters
if (!isStatic && parentClassSymbol != null) { if (!isStatic && parentClassSymbol != null) {
typeParameters += parentClassSymbol.fir.typeParameters.map { typeParameters += parentClassSymbol.fir.typeParameters.map {
@@ -188,10 +200,75 @@ class JavaSymbolProvider(
// TODO: may be we can process fields & methods later. // TODO: may be we can process fields & methods later.
// However, they should be built up to override resolve stage // However, they should be built up to override resolve stage
for (javaField in javaClass.fields) { for (javaField in javaClass.fields) {
declarations += convertJavaFieldToFir(javaField, classId, javaTypeParameterStack)
}
val valueParametersForAnnotationConstructor = ValueParametersForAnnotationConstructor()
val classIsAnnotation = classKind == ClassKind.ANNOTATION_CLASS
for (javaMethod in javaClass.methods) {
declarations += convertJavaMethodToFir(
javaMethod,
classId,
javaTypeParameterStack,
classIsAnnotation,
valueParametersForAnnotationConstructor
)
}
val javaClassDeclaredConstructors = javaClass.constructors
val constructorId = CallableId(classId.packageFqName, classId.relativeClassName, classId.shortClassName)
if (javaClassDeclaredConstructors.isEmpty()
&& javaClass.classKind == ClassKind.CLASS
&& javaClass.hasDefaultConstructor()
) {
declarations += convertJavaConstructorToFir(
javaConstructor = null,
constructorId,
javaClass,
ownerClassBuilder = this,
classTypeParameters,
javaTypeParameterStack
)
}
for (javaConstructor in javaClassDeclaredConstructors) {
declarations += convertJavaConstructorToFir(
javaConstructor,
constructorId,
javaClass,
ownerClassBuilder = this,
classTypeParameters,
javaTypeParameterStack,
)
}
if (classKind == ClassKind.ENUM_CLASS) {
generateValuesFunction(session, classId.packageFqName, classId.relativeClassName)
generateValueOfFunction(session, classId.packageFqName, classId.relativeClassName)
}
if (classIsAnnotation) {
declarations += buildConstructorForAnnotationClass(constructorId, this, valueParametersForAnnotationConstructor)
}
parentClassTypeParameterStackCache.remove(classSymbol)
}
firJavaClass.replaceSuperTypeRefs(
javaClass.supertypes.map { supertype ->
supertype.toFirResolvedTypeRef(
this@JavaSymbolProvider.session, javaTypeParameterStack, isForSupertypes = true, forTypeParameterBounds = false
)
}
)
return firJavaClass
}
private fun convertJavaFieldToFir(
javaField: JavaField,
classId: ClassId,
javaTypeParameterStack: JavaTypeParameterStack
): FirDeclaration {
val fieldName = javaField.name val fieldName = javaField.name
val fieldId = CallableId(classId.packageFqName, classId.relativeClassName, fieldName) val fieldId = CallableId(classId.packageFqName, classId.relativeClassName, fieldName)
val returnType = javaField.type val returnType = javaField.type
val firJavaDeclaration = when { return when {
javaField.isEnumEntry -> buildEnumEntry { javaField.isEnumEntry -> buildEnumEntry {
source = (javaField as? JavaElementImpl<*>)?.psi?.toFirPsiSourceElement() source = (javaField as? JavaElementImpl<*>)?.psi?.toFirPsiSourceElement()
session = this@JavaSymbolProvider.session session = this@JavaSymbolProvider.session
@@ -233,13 +310,15 @@ class JavaSymbolProvider(
addAnnotationsFrom(this@JavaSymbolProvider.session, javaField, javaTypeParameterStack) addAnnotationsFrom(this@JavaSymbolProvider.session, javaField, javaTypeParameterStack)
} }
} }
declarations += firJavaDeclaration
} }
val valueParametersForAnnotationConstructor = mutableListOf<FirJavaValueParameter>()
var valueParameterForValueInAnnotationConstructor: FirJavaValueParameter? = null
val classIsAnnotation = classKind == ClassKind.ANNOTATION_CLASS
for (javaMethod in javaClass.methods) { private fun convertJavaMethodToFir(
javaMethod: JavaMethod,
classId: ClassId,
javaTypeParameterStack: JavaTypeParameterStack,
classIsAnnotation: Boolean,
valueParametersForAnnotationConstructor: ValueParametersForAnnotationConstructor
): FirJavaMethod {
val methodName = javaMethod.name val methodName = javaMethod.name
val methodId = CallableId(classId.packageFqName, classId.relativeClassName, methodName) val methodId = CallableId(classId.packageFqName, classId.relativeClassName, methodName)
val methodSymbol = FirNamedFunctionSymbol(methodId) val methodSymbol = FirNamedFunctionSymbol(methodId)
@@ -289,35 +368,30 @@ class JavaSymbolProvider(
isVararg = javaMethod.returnType is JavaArrayType isVararg = javaMethod.returnType is JavaArrayType
} }
if (firJavaMethod.name == VALUE_METHOD_NAME) { if (firJavaMethod.name == VALUE_METHOD_NAME) {
valueParameterForValueInAnnotationConstructor = parameterForAnnotationConstructor valueParametersForAnnotationConstructor.valueParameterForValue = parameterForAnnotationConstructor
} else { } else {
valueParametersForAnnotationConstructor += parameterForAnnotationConstructor valueParametersForAnnotationConstructor.valueParameters += parameterForAnnotationConstructor
} }
} }
declarations += firJavaMethod return firJavaMethod
} }
val javaClassDeclaredConstructors = javaClass.constructors
val constructorId = CallableId(classId.packageFqName, classId.relativeClassName, classId.shortClassName)
fun buildSelfTypeRef() = firSymbol.constructType( private fun convertJavaConstructorToFir(
this@buildJavaClass.typeParameters.map { javaConstructor: JavaConstructor?,
ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) constructorId: CallableId,
}.toTypedArray(), javaClass: JavaClass,
false, ownerClassBuilder: FirJavaClassBuilder,
) classTypeParameters: List<FirTypeParameter>,
javaTypeParameterStack: JavaTypeParameterStack,
fun prepareJavaConstructor( ): FirJavaConstructor {
visibility: Visibility = this.visibility,
psi: PsiElement? = null,
isPrimary: Boolean = false,
): FirJavaConstructorBuilder {
val constructorSymbol = FirConstructorSymbol(constructorId) val constructorSymbol = FirConstructorSymbol(constructorId)
return FirJavaConstructorBuilder().apply { return buildJavaConstructor {
source = psi?.toFirPsiSourceElement() source = (javaConstructor as? JavaElementImpl<*>)?.psi?.toFirPsiSourceElement()
session = this@JavaSymbolProvider.session session = this@JavaSymbolProvider.session
symbol = constructorSymbol symbol = constructorSymbol
isInner = javaClass.outerClass != null && !javaClass.isStatic isInner = javaClass.outerClass != null && !javaClass.isStatic
val isThisInner = this.isInner val isThisInner = this.isInner
val visibility = javaConstructor?.visibility ?: ownerClassBuilder.visibility
status = FirResolvedDeclarationStatusImpl( status = FirResolvedDeclarationStatusImpl(
visibility, visibility,
Modality.FINAL Modality.FINAL
@@ -328,24 +402,13 @@ class JavaSymbolProvider(
isInner = isThisInner isInner = isThisInner
} }
this.visibility = visibility this.visibility = visibility
this.isPrimary = isPrimary isPrimary = javaConstructor == null
returnTypeRef = buildResolvedTypeRef { returnTypeRef = buildResolvedTypeRef {
type = buildSelfTypeRef() type = ownerClassBuilder.buildSelfTypeRef()
} }
typeParameters += classTypeParameters.map { buildConstructedClassTypeParameterRef { symbol = it.symbol } } typeParameters += classTypeParameters.map { buildConstructedClassTypeParameterRef { symbol = it.symbol } }
}
}
if (javaClassDeclaredConstructors.isEmpty() if (javaConstructor != null) {
&& javaClass.classKind == ClassKind.CLASS
&& javaClass.hasDefaultConstructor()) {
declarations += prepareJavaConstructor(isPrimary = true).build()
}
for (javaConstructor in javaClassDeclaredConstructors) {
declarations += prepareJavaConstructor(
visibility = javaConstructor.visibility,
psi = (javaConstructor as? JavaElementImpl<*>)?.psi,
).apply {
this.typeParameters += javaConstructor.typeParameters.convertTypeParameters(javaTypeParameterStack) this.typeParameters += javaConstructor.typeParameters.convertTypeParameters(javaTypeParameterStack)
addAnnotationsFrom(this@JavaSymbolProvider.session, javaConstructor, javaTypeParameterStack) addAnnotationsFrom(this@JavaSymbolProvider.session, javaConstructor, javaTypeParameterStack)
for ((index, valueParameter) in javaConstructor.valueParameters.withIndex()) { for ((index, valueParameter) in javaConstructor.valueParameters.withIndex()) {
@@ -353,40 +416,36 @@ class JavaSymbolProvider(
this@JavaSymbolProvider.session, index, javaTypeParameterStack, this@JavaSymbolProvider.session, index, javaTypeParameterStack,
) )
} }
}.build() }
}
} }
if (classKind == ClassKind.ENUM_CLASS) { private fun buildConstructorForAnnotationClass(
generateValuesFunction(session, classId.packageFqName, classId.relativeClassName) constructorId: CallableId,
generateValueOfFunction(session, classId.packageFqName, classId.relativeClassName) ownerClassBuilder: FirJavaClassBuilder,
} valueParametersForAnnotationConstructor: ValueParametersForAnnotationConstructor
if (classIsAnnotation) { ): FirJavaConstructor {
declarations += buildJavaConstructor { return buildJavaConstructor {
session = this@JavaSymbolProvider.session session = this@JavaSymbolProvider.session
symbol = FirConstructorSymbol(constructorId) symbol = FirConstructorSymbol(constructorId)
status = FirResolvedDeclarationStatusImpl(Visibilities.Public, Modality.FINAL) status = FirResolvedDeclarationStatusImpl(Visibilities.Public, Modality.FINAL)
returnTypeRef = buildResolvedTypeRef { returnTypeRef = buildResolvedTypeRef {
type = buildSelfTypeRef() type = ownerClassBuilder.buildSelfTypeRef()
} }
valueParameters.addIfNotNull(valueParameterForValueInAnnotationConstructor) valueParameters.addIfNotNull(valueParametersForAnnotationConstructor.valueParameterForValue)
valueParameters += valueParametersForAnnotationConstructor valueParameters += valueParametersForAnnotationConstructor.valueParameters
visibility = Visibilities.Public visibility = Visibilities.Public
isInner = false isInner = false
isPrimary = true isPrimary = true
} }
} }
parentClassTypeParameterStackCache.remove(firSymbol)
} private fun FirJavaClassBuilder.buildSelfTypeRef(): ConeKotlinType = symbol.constructType(
firJavaClass.replaceSuperTypeRefs( typeParameters.map {
javaClass.supertypes.map { supertype -> ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), isNullable = false)
supertype.toFirResolvedTypeRef( }.toTypedArray(),
this@JavaSymbolProvider.session, javaTypeParameterStack, isForSupertypes = true, forTypeParameterBounds = false isNullable = false,
) )
}
)
}
}
}
override fun getPackage(fqName: FqName): FqName? { override fun getPackage(fqName: FqName): FqName? {
return packageCache.lookupCacheOrCalculate(fqName) { return packageCache.lookupCacheOrCalculate(fqName) {