Implement FIR loading for Java (classes, supertypes, parameters, funs)
Properties aren't implemented yet FIR symbol provider functions return more specialized types now Related to KT-28918, KT-29636, KT-29218 #KT-28788 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
4ea3df53cc
commit
3a237416c9
@@ -27,7 +27,7 @@ class FirJavaModuleBasedSession(
|
||||
FirCompositeSymbolProvider(
|
||||
listOf(
|
||||
service<FirProvider>(),
|
||||
JavaSymbolProvider(sessionProvider.project, scope),
|
||||
JavaSymbolProvider(this, sessionProvider.project, scope),
|
||||
FirDependenciesSymbolProviderImpl(this)
|
||||
)
|
||||
)
|
||||
@@ -47,7 +47,7 @@ class FirLibrarySession(
|
||||
FirCompositeSymbolProvider(
|
||||
listOf(
|
||||
FirLibrarySymbolProviderImpl(this),
|
||||
JavaSymbolProvider(sessionProvider.project, scope),
|
||||
JavaSymbolProvider(this, sessionProvider.project, scope),
|
||||
FirDependenciesSymbolProviderImpl(this)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -7,29 +7,212 @@ package org.jetbrains.kotlin.fir.java
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.fir.java.symbols.JavaClassSymbol
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirNamedFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.fir.resolve.AbstractFirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinTypeProjection
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedType
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||
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.jvm.KotlinJavaPsiFacade
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
class JavaSymbolProvider(
|
||||
val session: FirSession,
|
||||
val project: Project,
|
||||
private val searchScope: GlobalSearchScope
|
||||
) : AbstractFirSymbolProvider() {
|
||||
override fun getCallableSymbols(callableId: CallableId): List<ConeSymbol> {
|
||||
// TODO
|
||||
return emptyList()
|
||||
|
||||
private val facade: KotlinJavaPsiFacade get() = KotlinJavaPsiFacade.getInstance(project)
|
||||
|
||||
private fun JavaAnnotation.toFirAnnotationCall(): FirAnnotationCall {
|
||||
return FirAnnotationCallImpl(
|
||||
session, psi = null, useSiteTarget = null,
|
||||
annotationType = FirResolvedTypeImpl(
|
||||
session = session,
|
||||
psi = null,
|
||||
type = ConeClassTypeImpl(FirClassSymbol(classId!!), emptyArray()),
|
||||
isNullable = true,
|
||||
annotations = emptyList()
|
||||
)
|
||||
).apply {
|
||||
for (argument in this@toFirAnnotationCall.arguments) {
|
||||
arguments += argument.toFirExpression()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getClassLikeSymbolByFqName(classId: ClassId): ConeSymbol? {
|
||||
return classCache.lookupCacheOrCalculate(classId) {
|
||||
val facade = KotlinJavaPsiFacade.getInstance(project)
|
||||
val foundClass = facade.findClass(JavaClassFinder.Request(classId), searchScope)
|
||||
foundClass?.let { javaClass -> JavaClassSymbol(javaClass) }
|
||||
private fun JavaAnnotationArgument.toFirExpression(): FirExpression {
|
||||
// TODO: this.name
|
||||
return when (this) {
|
||||
is JavaLiteralAnnotationArgument -> when (value) {
|
||||
null -> FirConstExpressionImpl(session, null, IrConstKind.Null, null)
|
||||
else -> FirErrorExpressionImpl(session, null, "Unknown value in JavaLiteralAnnotationArgument: $value")
|
||||
}
|
||||
is JavaArrayAnnotationArgument -> FirArrayOfCallImpl(session, null).apply {
|
||||
for (element in getElements()) {
|
||||
arguments += element.toFirExpression()
|
||||
}
|
||||
}
|
||||
// TODO
|
||||
//is JavaEnumValueAnnotationArgument -> {}
|
||||
is JavaClassObjectAnnotationArgument -> FirGetClassCallImpl(session, null).apply {
|
||||
// TODO
|
||||
//arguments += getReferencedType().toFirType()
|
||||
}
|
||||
is JavaAnnotationAsAnnotationArgument -> getAnnotation().toFirAnnotationCall()
|
||||
else -> FirErrorExpressionImpl(session, null, "Unknown JavaAnnotationArgument: ${this::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun JavaClassifierType.toFirResolvedType(): FirResolvedType {
|
||||
val coneType = when (val classifier = classifier) {
|
||||
is JavaClass -> {
|
||||
val symbol = session.service<FirSymbolProvider>().getClassLikeSymbolByFqName(classifier.classId!!) as ConeClassSymbol
|
||||
ConeClassTypeImpl(symbol, typeArguments = typeArguments.map { it.toConeProjection() }.toTypedArray())
|
||||
}
|
||||
is JavaTypeParameter -> {
|
||||
// TODO: it's unclear how to identify type parameter by the symbol
|
||||
// TODO: some type parameter cache (provider?)
|
||||
val symbol = createTypeParameterSymbol(classifier.name)
|
||||
ConeTypeParameterTypeImpl(symbol)
|
||||
}
|
||||
else -> ConeClassErrorType(reason = "Unexpected classifier: $classifier")
|
||||
}
|
||||
return FirResolvedTypeImpl(
|
||||
session, psi = null, type = coneType,
|
||||
isNullable = false, annotations = annotations.map { it.toFirAnnotationCall() }
|
||||
)
|
||||
}
|
||||
|
||||
private fun JavaType.toFirResolvedType(): FirResolvedType {
|
||||
if (this is JavaClassifierType) return toFirResolvedType()
|
||||
return FirResolvedTypeImpl(
|
||||
session, psi = null, type = ConeClassErrorType("Unexpected JavaType: $this"),
|
||||
isNullable = false, annotations = emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
private fun JavaType.toConeProjection(): ConeKotlinTypeProjection {
|
||||
if (this is JavaClassifierType) {
|
||||
return toFirResolvedType().type
|
||||
}
|
||||
return ConeClassErrorType("Unexpected type argument: $this")
|
||||
}
|
||||
|
||||
private fun createTypeParameterSymbol(name: Name): FirTypeParameterSymbol {
|
||||
val firSymbol = FirTypeParameterSymbol()
|
||||
FirTypeParameterImpl(session, null, firSymbol, name, variance = Variance.INVARIANT, isReified = false)
|
||||
return firSymbol
|
||||
}
|
||||
|
||||
private fun FirAbstractAnnotatedElement.addAnnotationsFrom(javaAnnotationOwner: JavaAnnotationOwner) {
|
||||
for (annotation in javaAnnotationOwner.annotations) {
|
||||
annotations += annotation.toFirAnnotationCall()
|
||||
}
|
||||
}
|
||||
|
||||
private fun findClass(classId: ClassId): JavaClass? = facade.findClass(JavaClassFinder.Request(classId), searchScope)
|
||||
|
||||
override fun getCallableSymbols(callableId: CallableId): List<ConeCallableSymbol> {
|
||||
return callableCache.lookupCacheOrCalculate(callableId) {
|
||||
val classId = callableId.classId ?: return@lookupCacheOrCalculate emptyList()
|
||||
val classSymbol = getClassLikeSymbolByFqName(classId) as? FirClassSymbol
|
||||
?: return@lookupCacheOrCalculate emptyList()
|
||||
val firClass = classSymbol.fir as FirModifiableClass
|
||||
val callableSymbols = mutableListOf<ConeCallableSymbol>()
|
||||
findClass(classId)?.let { javaClass ->
|
||||
if (firClass.declarations.isEmpty()) {
|
||||
for (javaMethod in javaClass.methods) {
|
||||
val methodName = javaMethod.name
|
||||
val methodId = CallableId(callableId.packageName, callableId.className, methodName)
|
||||
val methodSymbol = FirFunctionSymbol(methodId)
|
||||
val memberFunction = FirMemberFunctionImpl(
|
||||
session, null, methodSymbol, methodName,
|
||||
javaMethod.visibility, javaMethod.modality,
|
||||
isExpect = false, isActual = false, isOverride = false,
|
||||
isOperator = true, isInfix = false, isInline = false,
|
||||
isTailRec = false, isExternal = false, isSuspend = false,
|
||||
receiverType = null, returnType = javaMethod.returnType.toFirResolvedType()
|
||||
).apply {
|
||||
for (typeParameter in javaMethod.typeParameters) {
|
||||
typeParameters += createTypeParameterSymbol(typeParameter.name).fir
|
||||
}
|
||||
addAnnotationsFrom(javaMethod)
|
||||
for (valueParameter in javaMethod.valueParameters) {
|
||||
valueParameters += FirValueParameterImpl(
|
||||
session, null, valueParameter.name ?: Name.special("<anonymous Java parameter>"),
|
||||
returnType = valueParameter.type.toFirResolvedType(),
|
||||
defaultValue = null, isCrossinline = false, isNoinline = false,
|
||||
isVararg = valueParameter.isVararg
|
||||
)
|
||||
}
|
||||
}
|
||||
firClass.declarations += memberFunction
|
||||
}
|
||||
}
|
||||
for (declaration in firClass.declarations) {
|
||||
if (declaration is FirNamedFunction) {
|
||||
val methodId = CallableId(callableId.packageName, callableId.className, declaration.name)
|
||||
if (methodId == callableId) {
|
||||
val symbol = declaration.symbol as ConeCallableSymbol
|
||||
callableSymbols += symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
callableSymbols
|
||||
}.orEmpty()
|
||||
}
|
||||
|
||||
override fun getClassLikeSymbolByFqName(classId: ClassId): ConeClassLikeSymbol? {
|
||||
return classCache.lookupCacheOrCalculateWithPostCompute(classId, {
|
||||
val foundClass = findClass(classId)
|
||||
if (foundClass == null) {
|
||||
null to null
|
||||
} else {
|
||||
FirClassSymbol(classId) to foundClass
|
||||
}
|
||||
}) { firSymbol, foundClass ->
|
||||
foundClass?.let { javaClass ->
|
||||
FirClassImpl(
|
||||
session, null, firSymbol as FirClassSymbol, javaClass.name,
|
||||
javaClass.visibility, javaClass.modality,
|
||||
isExpect = false, isActual = false,
|
||||
classKind = javaClass.classKind,
|
||||
isInner = !javaClass.isStatic, isCompanion = false,
|
||||
isData = false, isInline = false
|
||||
).apply {
|
||||
for (typeParameter in javaClass.typeParameters) {
|
||||
typeParameters += createTypeParameterSymbol(typeParameter.name).fir
|
||||
}
|
||||
addAnnotationsFrom(javaClass)
|
||||
for (supertype in javaClass.supertypes) {
|
||||
superTypes += supertype.toFirResolvedType()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.fir.java
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaModifierListOwner
|
||||
|
||||
internal val JavaModifierListOwner.modality: Modality
|
||||
get() = when {
|
||||
isAbstract -> Modality.ABSTRACT
|
||||
isFinal -> Modality.FINAL
|
||||
else -> Modality.OPEN
|
||||
}
|
||||
|
||||
internal val JavaClass.classKind: ClassKind
|
||||
get() = when {
|
||||
isAnnotationType -> ClassKind.ANNOTATION_CLASS
|
||||
isInterface -> ClassKind.INTERFACE
|
||||
isEnum -> ClassKind.ENUM_CLASS
|
||||
else -> ClassKind.CLASS
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.fir.java.symbols
|
||||
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassSymbol
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.classId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
class JavaClassSymbol(javaClass: JavaClass) : ConeClassSymbol {
|
||||
override val classId: ClassId = javaClass.classId ?: error("!")
|
||||
}
|
||||
|
||||
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.fir.java.symbols
|
||||
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class JavaTypeParameterSymbol(override val name: Name) : ConeTypeParameterSymbol
|
||||
Reference in New Issue
Block a user