FIR: introduce element kind for source elements

It is needed for FIR IDE to determine if FIR element was built by PSI
or it is generated one
This commit is contained in:
Ilya Kirillov
2020-06-15 17:26:14 +03:00
parent f6e653b242
commit 94967bcd00
13 changed files with 305 additions and 127 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.
*/
@@ -32,12 +32,13 @@ private val VALUE = Name.identifier("value")
fun FirRegularClassBuilder.generateValuesFunction(
session: FirSession, packageFqName: FqName, classFqName: FqName, makeExpect: Boolean = false
) {
val sourceElement = source?.withKind(FirFakeSourceElementKind.EnumGeneratedDeclaration)
declarations += buildSimpleFunction {
source = this@generateValuesFunction.source
source = sourceElement
origin = FirDeclarationOrigin.Source
this.session = session
returnTypeRef = buildResolvedTypeRef {
source = this@generateValuesFunction.source
source = sourceElement
type = ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(StandardClassIds.Array),
arrayOf(
@@ -60,12 +61,13 @@ fun FirRegularClassBuilder.generateValuesFunction(
fun FirRegularClassBuilder.generateValueOfFunction(
session: FirSession, packageFqName: FqName, classFqName: FqName, makeExpect: Boolean = false
) {
val sourceElement = source?.withKind(FirFakeSourceElementKind.EnumGeneratedDeclaration)
declarations += buildSimpleFunction {
source = this@generateValueOfFunction.source
source = sourceElement
origin = FirDeclarationOrigin.Source
this.session = session
returnTypeRef = buildResolvedTypeRef {
source = this@generateValueOfFunction.source
source = sourceElement
type = ConeClassLikeTypeImpl(
this@generateValueOfFunction.symbol.toLookupTag(),
emptyArray(),
@@ -79,7 +81,7 @@ fun FirRegularClassBuilder.generateValueOfFunction(
}
symbol = FirNamedFunctionSymbol(CallableId(packageFqName, classFqName, ENUM_VALUE_OF))
valueParameters += buildValueParameter vp@{
source = this@generateValueOfFunction.source
source = sourceElement
origin = FirDeclarationOrigin.Source
this@vp.session = session
returnTypeRef = FirImplicitStringTypeRef(source)
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.
*/
@@ -10,13 +10,145 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import com.intellij.util.diff.FlyweightCapableTreeStructure
sealed class FirSourceElementKind
object FirRealSourceElementKind : FirSourceElementKind()
sealed class FirFakeSourceElementKind : FirSourceElementKind() {
// for some fir expression implicit return typeRef is generated
// some of them are: break, continue, return, throw, string concat,
// destruction parameters, function literals, explicitly boolean expressions
object ImplicitTypeRef : FirFakeSourceElementKind()
// for each class special class self type ref is created
// and have a fake source referencing it
object ClassSelfTypeRef : FirFakeSourceElementKind()
// FirErrorTypeRef may be built using unresolved firExpression
// and have a fake source referencing it
object ErrorTypeRef : FirFakeSourceElementKind()
// for properties without accessors default getter & setter are generated
// they have a fake source which refers to property
object DefaultAccessor : FirFakeSourceElementKind()
// for kt classes without implicit primary constructor one is generated
// with a fake source which refers to containing class
object ImplicitConstructor : FirFakeSourceElementKind()
// for constructors which do not have delegated constructor call the fake one is generated
// with a fake sources which refers to the original constructor
object DelegatingConstructorCall : FirFakeSourceElementKind()
// for enum entry with bodies the initializer in a form of anonymous object is generated
// with a fake sources which refers to the enum entry
object EnumInitializer : FirFakeSourceElementKind()
// for lambdas with implicit return the return statement is generated which is labeled
// with a fake sources which refers to the target expression
object GeneratedLambdaLabel : FirFakeSourceElementKind()
// for lambdas & functions with expression bodies the return statement is added
// with a fake sources which refers to the return target
object ImplicitReturn : FirFakeSourceElementKind()
// return expression in procedures -> return Unit
// with a fake sources which refers to the return statement
object ImplicitUnit : FirFakeSourceElementKind()
// delegates are wrapped into FirWrappedDelegateExpression
// with a fake sources which refers to delegated expression
object WrappedDelegate : FirFakeSourceElementKind()
// `for (i in list) { println(i) }` is converted to
// ```
// val <iterator>: = list.iterator()
// while(<iterator>.hasNext()) {
// val i = <iterator>.next()
// println(i)
// }
// ```
// where the generated WHILE loop has source element of initial FOR loop,
// other generated elements are marked as fake ones
object DesugaredForLoop : FirFakeSourceElementKind()
object ImplicitInvokeCall : FirFakeSourceElementKind()
// this/super expressions have FirThisReference/FirSuperReference
// with a fake sources which refers to this this/super expression
object ExplicitThisOrSuperReference : FirFakeSourceElementKind()
// for enum classes we have valueOf & values functions generated
// with a fake sources which refers to this the enum class
object EnumGeneratedDeclaration : FirFakeSourceElementKind()
// when (x) { "abc" -> 42 } --> when(val $subj = x) { $subj == "abc" -> 42 }
// where $subj == "42" has fake psi source which refers to "42" as inner expression
// and $subj fake source refers to "42" as KtWhenCondition
object WhenCondition : FirFakeSourceElementKind()
// for primary constructor parameter the corresponding class property is generated
// with a fake sources which refers to this the corresponding parameter
object PropertyFromParameter : FirFakeSourceElementKind()
// if (true) 1 --> if(true) { 1 }
// with a fake sources for the block which refers to the wrapped expression
object SingleExpressionBlock : FirFakeSourceElementKind()
// x++ -> x = x.inc()
// x = x++ -> x = { val <unary> = x; x = <unary>.inc(); <unary> }
object DesugaredIncrementOrDecrement : FirFakeSourceElementKind()
// x !in list --> !(x in list) where ! and !(x in list) will have a fake source
object DesugaredInvertedContains : FirFakeSourceElementKind()
// for data classes fir generates componentN() & copy() functions
// for componentN() functions the source will refer to the corresponding param and will be marked as a fake one
// for copy() functions the source will refer class to the param and will be marked as a fake one
object DataClassGeneratedMembers : FirFakeSourceElementKind()
// (vararg x: Int) --> (x: Array<out Int>) where array type ref has a fake source kind
object ArrayTypeFromVarargParameter : FirFakeSourceElementKind()
// val (a,b) = x --> val a = x.component1(); val b = x.component2()
// where componentN calls will have the fake source elements refer to the corresponding KtDestructuringDeclarationEntry
object DesugaredComponentFunctionCall : FirFakeSourceElementKind()
// when smart casts applied to the expression, its wrapped into FirExpressionWithSmartcast
// which type reference will have a fake source refer to a original source element of it
object SmartCastedTypeRef : FirFakeSourceElementKind()
// for safe call expressions like a?.foo() the FirSafeCallExpression is generated
// and it have a fake source
object DesugaredSafeCallExpression : FirFakeSourceElementKind()
// a += 2 --> a = a + 2
// where a + 2 will have a fake source
object DesugaredCompoundAssignment : FirFakeSourceElementKind()
//"$a" --> a.toString() where toString call source is marked as a fake one
object GeneratedToStringCallOnTemplateEntry : FirFakeSourceElementKind()
// `a > b` will be wrapped in FirComparisonExpression
// with real source which points to initial `a > b` expression
// and inner FirFunctionCall will refer to a fake source
object GeneratedCompararisonExpression : FirFakeSourceElementKind()
// a ?: b --> when(val $subj = a) { .... }
// where `val $subj = a` has a fake source
object WhenGeneratedSubject : FirFakeSourceElementKind()
}
sealed class FirSourceElement {
abstract val elementType: IElementType
abstract val startOffset: Int
abstract val endOffset: Int
abstract val kind: FirSourceElementKind
}
class FirPsiSourceElement<out P : PsiElement>(val psi: P) : FirSourceElement() {
sealed class FirPsiSourceElement<out P : PsiElement>(val psi: P) : FirSourceElement() {
override val elementType: IElementType
get() = psi.node.elementType
@@ -27,6 +159,24 @@ class FirPsiSourceElement<out P : PsiElement>(val psi: P) : FirSourceElement() {
get() = psi.textRange.endOffset
}
class FirRealPsiSourceElement<out P : PsiElement>(psi: P) : FirPsiSourceElement<P>(psi) {
override val kind: FirSourceElementKind get() = FirRealSourceElementKind
}
class FirFakeSourceElement<out P : PsiElement>(psi: P, override val kind: FirFakeSourceElementKind) : FirPsiSourceElement<P>(psi)
fun FirSourceElement.withKind(newKind: FirSourceElementKind?): FirSourceElement {
if (newKind == null) return this
return when (this) {
is FirLightSourceElement -> this
is FirPsiSourceElement<*> -> when (newKind) {
kind -> this
FirRealSourceElementKind -> FirRealPsiSourceElement(psi)
is FirFakeSourceElementKind -> FirFakeSourceElement(psi, newKind)
}
}
}
class FirLightSourceElement(
val element: LighterASTNode,
override val startOffset: Int,
@@ -35,14 +185,20 @@ class FirLightSourceElement(
) : FirSourceElement() {
override val elementType: IElementType
get() = element.tokenType
override val kind: FirSourceElementKind get() = FirRealSourceElementKind
}
val FirSourceElement?.psi: PsiElement? get() = (this as? FirPsiSourceElement<*>)?.psi
val FirElement.psi: PsiElement? get() = (source as? FirPsiSourceElement<*>)?.psi
val FirElement.realPsi: PsiElement? get() = (source as? FirRealPsiSourceElement<*>)?.psi
@Suppress("NOTHING_TO_INLINE")
inline fun PsiElement.toFirPsiSourceElement(): FirPsiSourceElement<*> = FirPsiSourceElement(this)
inline fun PsiElement.toFirPsiSourceElement(kind: FirSourceElementKind = FirRealSourceElementKind): FirPsiSourceElement<*> = when (kind) {
is FirRealSourceElementKind -> FirRealPsiSourceElement(this)
is FirFakeSourceElementKind -> FirFakeSourceElement(this, kind)
}
@Suppress("NOTHING_TO_INLINE")
inline fun LighterASTNode.toFirLightSourceElement(