Analysis API: rework data model of resolve call API
This commit is contained in:
committed by
Ilya Kirillov
parent
58067e0a1e
commit
53b3893738
@@ -7,171 +7,477 @@ package org.jetbrains.kotlin.analysis.api.calls
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.ValidityTokenOwner
|
||||
import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnostic
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtVariableLikeSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
/**
|
||||
* Represents direct or indirect (via invoke) function call from Kotlin code
|
||||
* Call information at call site.
|
||||
*/
|
||||
public sealed class KtCall : ValidityTokenOwner {
|
||||
public abstract val isErrorCall: Boolean
|
||||
public abstract val argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>
|
||||
public abstract val targetFunction: KtCallTarget
|
||||
public abstract val substitutor: KtSubstitutor
|
||||
}
|
||||
public sealed class KtCallInfo : ValidityTokenOwner
|
||||
|
||||
/**
|
||||
* Call using `()` of some variable of functional type, e.g.,
|
||||
*
|
||||
* fun x(f: () -> Int) {
|
||||
* f() // functional type call
|
||||
* }
|
||||
* Successfully resolved call.
|
||||
*/
|
||||
public class KtFunctionalTypeVariableCall(
|
||||
private val _target: KtVariableLikeSymbol,
|
||||
private val _argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>,
|
||||
private val _targetFunction: KtCallTarget,
|
||||
private val _substitutor: KtSubstitutor,
|
||||
public class KtSuccessCallInfo(private val _call: KtCall) : KtCallInfo() {
|
||||
override val token: ValidityToken
|
||||
) : KtCall() {
|
||||
public val target: KtVariableLikeSymbol get() = withValidityAssertion { _target }
|
||||
override val isErrorCall: Boolean get() = withValidityAssertion { false }
|
||||
override val argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>
|
||||
get() = withValidityAssertion { _argumentMapping }
|
||||
override val targetFunction: KtCallTarget
|
||||
get() = withValidityAssertion { _targetFunction }
|
||||
override val substitutor: KtSubstitutor
|
||||
get() = withValidityAssertion { _substitutor }
|
||||
get() = _call.token
|
||||
public val call: KtCall get() = withValidityAssertion { _call }
|
||||
}
|
||||
|
||||
/**
|
||||
* Direct or indirect call of function declared by user
|
||||
* Call that contains errors.
|
||||
*/
|
||||
public sealed class KtDeclaredFunctionCall : KtCall() {
|
||||
override val isErrorCall: Boolean
|
||||
get() = withValidityAssertion { targetFunction is KtErrorCallTarget }
|
||||
}
|
||||
|
||||
/**
|
||||
* Call using () on variable on some non-functional type, considers that `invoke` function is declared somewhere
|
||||
*
|
||||
* fun x(y: Int) {
|
||||
* y() // variable with invoke function call
|
||||
* }
|
||||
*
|
||||
* fun Int.invoke() {}
|
||||
*/
|
||||
public class KtVariableWithInvokeFunctionCall(
|
||||
private val _target: KtVariableLikeSymbol,
|
||||
private val _argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>,
|
||||
private val _targetFunction: KtCallTarget,
|
||||
private val _substitutor: KtSubstitutor,
|
||||
override val token: ValidityToken
|
||||
) : KtDeclaredFunctionCall() {
|
||||
public val target: KtVariableLikeSymbol get() = withValidityAssertion { _target }
|
||||
override val argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>
|
||||
get() = withValidityAssertion { _argumentMapping }
|
||||
override val targetFunction: KtCallTarget
|
||||
get() = withValidityAssertion { _targetFunction }
|
||||
override val substitutor: KtSubstitutor
|
||||
get() = withValidityAssertion { _substitutor }
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple function call, e.g.,
|
||||
*
|
||||
* x.toString() // function call
|
||||
*/
|
||||
public class KtFunctionCall(
|
||||
private val _argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>,
|
||||
private val _targetFunction: KtCallTarget,
|
||||
private val _substitutor: KtSubstitutor,
|
||||
override val token: ValidityToken
|
||||
) : KtDeclaredFunctionCall() {
|
||||
override val argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>
|
||||
get() = withValidityAssertion { _argumentMapping }
|
||||
override val targetFunction: KtCallTarget
|
||||
get() = withValidityAssertion { _targetFunction }
|
||||
override val substitutor: KtSubstitutor
|
||||
get() = withValidityAssertion { _substitutor }
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation call, e.g.,
|
||||
*
|
||||
* @Retention(AnnotationRetention.SOURCE) // annotation call
|
||||
* annotation class Ann
|
||||
*/
|
||||
public class KtAnnotationCall(
|
||||
private val _argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>,
|
||||
private val _targetFunction: KtCallTarget,
|
||||
override val token: ValidityToken
|
||||
) : KtDeclaredFunctionCall() {
|
||||
override val argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>
|
||||
get() = withValidityAssertion { _argumentMapping }
|
||||
override val targetFunction: KtCallTarget
|
||||
get() = withValidityAssertion { _targetFunction }
|
||||
|
||||
// Type parameter is allowed for an annotation class but not allowed as members. So substitutor is probably never useful.
|
||||
override val substitutor: KtSubstitutor = KtSubstitutor.Empty(token)
|
||||
}
|
||||
// TODO: Add other properties, e.g., useSiteTarget
|
||||
|
||||
/**
|
||||
* Delegated constructor call, e.g.,
|
||||
*
|
||||
* open class A(a: Int)
|
||||
* class B(b: Int) : A(b) { // delegated constructor call (kind = SUPER_CALL)
|
||||
* constructor() : this(1) // delegated constructor call (kind = THIS_CALL)
|
||||
* }
|
||||
*/
|
||||
public class KtDelegatedConstructorCall(
|
||||
private val _argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>,
|
||||
private val _targetFunction: KtCallTarget,
|
||||
public val kind: KtDelegatedConstructorCallKind,
|
||||
override val token: ValidityToken
|
||||
) : KtDeclaredFunctionCall() {
|
||||
override val argumentMapping: LinkedHashMap<KtExpression, KtValueParameterSymbol>
|
||||
get() = withValidityAssertion { _argumentMapping }
|
||||
override val targetFunction: KtCallTarget
|
||||
get() = withValidityAssertion { _targetFunction }
|
||||
|
||||
// A delegate constructor call never has any type argument.
|
||||
override val substitutor: KtSubstitutor = KtSubstitutor.Empty(token)
|
||||
}
|
||||
|
||||
public enum class KtDelegatedConstructorCallKind { SUPER_CALL, THIS_CALL }
|
||||
|
||||
/**
|
||||
* Represents function(s) in which call was resolved,
|
||||
* Can be success [KtSuccessCallTarget] in this case there only one such function
|
||||
* Or erroneous [KtErrorCallTarget] in this case there can be any count of candidates
|
||||
*/
|
||||
public sealed class KtCallTarget : ValidityTokenOwner {
|
||||
public abstract val candidates: Collection<KtFunctionLikeSymbol>
|
||||
}
|
||||
|
||||
/**
|
||||
* Success call of [symbol]
|
||||
*/
|
||||
public class KtSuccessCallTarget(private val _symbol: KtFunctionLikeSymbol, override val token: ValidityToken) : KtCallTarget() {
|
||||
public val symbol: KtFunctionLikeSymbol get() = withValidityAssertion { _symbol }
|
||||
override val candidates: Collection<KtFunctionLikeSymbol> get() = withValidityAssertion { listOf(symbol) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Function call with errors, possible candidates are [candidates]
|
||||
*/
|
||||
public class KtErrorCallTarget(
|
||||
private val _candidates: Collection<KtFunctionLikeSymbol>,
|
||||
public class KtErrorCallInfo(
|
||||
private val _candidateCalls: List<KtCall>,
|
||||
private val _diagnostic: KtDiagnostic,
|
||||
override val token: ValidityToken
|
||||
) : KtCallTarget() {
|
||||
) : KtCallInfo() {
|
||||
public val candidateCalls: List<KtCall> get() = withValidityAssertion { _candidateCalls }
|
||||
public val diagnostic: KtDiagnostic get() = withValidityAssertion { _diagnostic }
|
||||
override val candidates: Collection<KtFunctionLikeSymbol> get() = withValidityAssertion { _candidates }
|
||||
}
|
||||
}
|
||||
|
||||
public val KtCallInfo.calls: List<KtCall>
|
||||
get() = when (this) {
|
||||
is KtErrorCallInfo -> candidateCalls
|
||||
is KtSuccessCallInfo -> listOf(call)
|
||||
}
|
||||
|
||||
public inline fun <reified T : KtCall> KtCallInfo.singleCallOrNull(): T? {
|
||||
return calls.singleOrNull { it is T } as T?
|
||||
}
|
||||
|
||||
public fun KtCallInfo.singleFunctionCallOrNull(): KtFunctionCall<*>? = singleCallOrNull()
|
||||
public fun KtCallInfo.singleVariableAccessCall(): KtVariableAccessCall? = singleCallOrNull()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public fun KtCallInfo.singleConstructorCallOrNull(): KtFunctionCall<KtConstructorSymbol>? =
|
||||
singleCallOrNull<KtFunctionCall<*>>()?.takeIf { it.symbol is KtConstructorSymbol } as KtFunctionCall<KtConstructorSymbol>?
|
||||
|
||||
public inline fun <reified T : KtCall> KtCallInfo.successfulCallOrNull(): T? {
|
||||
return (this as? KtSuccessCallInfo)?.call as? T
|
||||
}
|
||||
|
||||
public fun KtCallInfo.successfulFunctionCallOrNull(): KtFunctionCall<*>? = successfulCallOrNull()
|
||||
public fun KtCallInfo.successfulVariableAccessCall(): KtVariableAccessCall? = successfulCallOrNull()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public fun KtCallInfo.successfulConstructorCallOrNull(): KtFunctionCall<KtConstructorSymbol>? =
|
||||
successfulCallOrNull<KtFunctionCall<*>>()?.takeIf { it.symbol is KtConstructorSymbol } as KtFunctionCall<KtConstructorSymbol>?
|
||||
/**
|
||||
* A call to a function, a simple/compound access to a property, or a simple/compound access through `get` and `set` convention.
|
||||
*/
|
||||
public sealed class KtCall : ValidityTokenOwner
|
||||
|
||||
/**
|
||||
* A callable symbol partially applied with receivers and type arguments. Essentially, this is a call that misses some information. For
|
||||
* properties, the missing information is the type of access (read, write, or compound access) to this property. For functions, the missing
|
||||
* information is the value arguments for the call.
|
||||
*/
|
||||
public class KtPartiallyAppliedSymbol<out S : KtCallableSymbol, out C : KtSignature<S>>(
|
||||
private val _signature: C,
|
||||
private val _dispatchReceiver: KtReceiverValue?,
|
||||
private val _extensionReceiver: KtReceiverValue?,
|
||||
) : ValidityTokenOwner {
|
||||
|
||||
override val token: ValidityToken get() = _signature.token
|
||||
|
||||
/**
|
||||
* The function or variable (property) declaration.
|
||||
*/
|
||||
public val signature: C get() = withValidityAssertion { _signature }
|
||||
|
||||
/**
|
||||
* The dispatch receiver for this symbol access. Dispatch receiver is available if the symbol is declared inside a class or object.
|
||||
*/
|
||||
public val dispatchReceiver: KtReceiverValue? get() = withValidityAssertion { _dispatchReceiver }
|
||||
|
||||
/**
|
||||
* The extension receiver for this symbol access. Extension receiver is available if the symbol is declared with an extension receiver.
|
||||
*/
|
||||
public val extensionReceiver: KtReceiverValue? get() = withValidityAssertion { _extensionReceiver }
|
||||
}
|
||||
|
||||
public val <S : KtCallableSymbol, C : KtSignature<S>> KtPartiallyAppliedSymbol<S, C>.symbol: S get() = signature.symbol
|
||||
|
||||
/**
|
||||
* A synthetic call to assert an expression is not null. For example
|
||||
* ```
|
||||
* fun test(s: String?) {
|
||||
* s!!.length // Here the receiver is a `KtCheckNotNullCall` with base expression `s`.
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
public class KtCheckNotNullCall(
|
||||
override val token: ValidityToken,
|
||||
private val _baseExpression: KtExpression,
|
||||
) : KtCall() {
|
||||
public val baseExpression: KtExpression get() = withValidityAssertion { _baseExpression }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a function, or a simple/compound access to a property.
|
||||
*/
|
||||
public sealed class KtCallableMemberCall<S : KtCallableSymbol, C : KtSignature<S>> : KtCall() {
|
||||
public abstract val partiallyAppliedSymbol: KtPartiallyAppliedSymbol<S, C>
|
||||
}
|
||||
|
||||
public val <S : KtCallableSymbol, C : KtSignature<S>> KtCallableMemberCall<S, C>.symbol: S get() = partiallyAppliedSymbol.symbol
|
||||
|
||||
public sealed class KtFunctionCall<S : KtFunctionLikeSymbol>(
|
||||
private val _argumentMapping: LinkedHashMap<KtExpression, KtVariableLikeSignature<KtValueParameterSymbol>>,
|
||||
) : KtCallableMemberCall<S, KtFunctionLikeSignature<S>>() {
|
||||
|
||||
/**
|
||||
* The mapping from argument to parameter declaration. In case of vararg parameters, multiple arguments may be mapped to the same
|
||||
* `KtValueParameterSymbol`.
|
||||
*/
|
||||
public val argumentMapping: LinkedHashMap<KtExpression, KtVariableLikeSignature<KtValueParameterSymbol>> get() = withValidityAssertion { _argumentMapping }
|
||||
}
|
||||
|
||||
public typealias KtPartiallyAppliedFunctionSymbol<S> = KtPartiallyAppliedSymbol<S, KtFunctionLikeSignature<S>>
|
||||
|
||||
/**
|
||||
* A call to a function.
|
||||
*/
|
||||
public class KtSimpleFunctionCall(
|
||||
private val _partiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtFunctionLikeSymbol>,
|
||||
argumentMapping: LinkedHashMap<KtExpression, KtVariableLikeSignature<KtValueParameterSymbol>>,
|
||||
private val _isImplicitInvoke: Boolean,
|
||||
) : KtFunctionCall<KtFunctionLikeSymbol>(argumentMapping) {
|
||||
override val token: ValidityToken get() = _partiallyAppliedSymbol.token
|
||||
|
||||
/**
|
||||
* The function and receivers for this call.
|
||||
*/
|
||||
override val partiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtFunctionLikeSymbol> get() = withValidityAssertion { _partiallyAppliedSymbol }
|
||||
|
||||
/**
|
||||
* Whether this function call is an implicit invoke call on a value that has an `invoke` member function. See
|
||||
* https://kotlinlang.org/docs/operator-overloading.html#invoke-operator for more details.
|
||||
*/
|
||||
public val isImplicitInvoke: Boolean get() = withValidityAssertion { _isImplicitInvoke }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to an annotation. For example
|
||||
* ```
|
||||
* @Deprecated("foo") // call to annotation constructor with single argument `"foo"`.
|
||||
* fun foo() {}
|
||||
* ```
|
||||
*/
|
||||
public class KtAnnotationCall(
|
||||
private val _partiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtConstructorSymbol>,
|
||||
argumentMapping: LinkedHashMap<KtExpression, KtVariableLikeSignature<KtValueParameterSymbol>>,
|
||||
) : KtFunctionCall<KtConstructorSymbol>(argumentMapping) {
|
||||
override val token: ValidityToken get() = _partiallyAppliedSymbol.token
|
||||
|
||||
/**
|
||||
* The function and receivers for this call.
|
||||
*/
|
||||
override val partiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtConstructorSymbol> get() = withValidityAssertion { _partiallyAppliedSymbol }
|
||||
}
|
||||
|
||||
/**
|
||||
* A delegated call to constructors. For example
|
||||
* ```
|
||||
* open class SuperClass(i: Int)
|
||||
* class SubClass1: SuperClass(1) // a call to constructor of `SuperClass` with single argument `1`
|
||||
* class SubClass2 : SuperClass {
|
||||
* constructor(i: Int): super(i) {} // a call to constructor of `SuperClass` with single argument `i`
|
||||
* constructor(): this(2) {} // a call to constructor of `SubClass2` with single argument `2`.
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
public class KtDelegatedConstructorCall(
|
||||
private val _partiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtConstructorSymbol>,
|
||||
private val _kind: Kind,
|
||||
argumentMapping: LinkedHashMap<KtExpression, KtVariableLikeSignature<KtValueParameterSymbol>>,
|
||||
) : KtFunctionCall<KtConstructorSymbol>(argumentMapping) {
|
||||
override val token: ValidityToken get() = _partiallyAppliedSymbol.token
|
||||
|
||||
/**
|
||||
* The function and receivers for this call.
|
||||
*/
|
||||
override val partiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtConstructorSymbol> get() = withValidityAssertion { _partiallyAppliedSymbol }
|
||||
|
||||
public val kind: Kind get() = withValidityAssertion { _kind }
|
||||
|
||||
public enum class Kind { SUPER_CALL, THIS_CALL }
|
||||
}
|
||||
|
||||
/**
|
||||
* An access to variables (including properties).
|
||||
*/
|
||||
public sealed class KtVariableAccessCall : KtCallableMemberCall<KtVariableLikeSymbol, KtVariableLikeSignature<KtVariableLikeSymbol>>()
|
||||
|
||||
public typealias KtPartiallyAppliedVariableSymbol<S> = KtPartiallyAppliedSymbol<S, KtVariableLikeSignature<S>>
|
||||
|
||||
/**
|
||||
* A simple read or write to a variable or property.
|
||||
*/
|
||||
public class KtSimpleVariableAccessCall(
|
||||
private val _partiallyAppliedSymbol: KtPartiallyAppliedVariableSymbol<KtVariableLikeSymbol>,
|
||||
private val _simpleAccess: KtSimpleVariableAccess
|
||||
) : KtVariableAccessCall() {
|
||||
|
||||
override val token: ValidityToken get() = _partiallyAppliedSymbol.token
|
||||
|
||||
override val partiallyAppliedSymbol: KtPartiallyAppliedVariableSymbol<KtVariableLikeSymbol> get() = withValidityAssertion { _partiallyAppliedSymbol }
|
||||
|
||||
/**
|
||||
* The type of access to this property.
|
||||
*/
|
||||
public val simpleAccess: KtSimpleVariableAccess get() = withValidityAssertion { _simpleAccess }
|
||||
}
|
||||
|
||||
public sealed class KtSimpleVariableAccess {
|
||||
public object Read : KtSimpleVariableAccess()
|
||||
|
||||
public class Write(
|
||||
/**
|
||||
* [KtExpression] that represents the new value that should be assigned to this variable. Or null if the assignment is incomplete
|
||||
* and misses the new value.
|
||||
*/
|
||||
public val value: KtExpression?
|
||||
) : KtSimpleVariableAccess()
|
||||
}
|
||||
|
||||
public interface KtCompoundAccessCall {
|
||||
/**
|
||||
* The type of this compound access.
|
||||
*/
|
||||
public val compoundAccess: KtCompoundAccess
|
||||
}
|
||||
|
||||
/**
|
||||
* A compound access of a mutable variable. For example
|
||||
* ```
|
||||
* fun test() {
|
||||
* var i = 0
|
||||
* i += 1
|
||||
* // partiallyAppliedSymbol: {
|
||||
* // symbol: `i`
|
||||
* // dispatchReceiver: null
|
||||
* // extensionReceiver: null
|
||||
* // }
|
||||
* // accessType: OpAssign {
|
||||
* // kind: PLUS
|
||||
* // operand: 1
|
||||
* // operationSymbol: Int.plus()
|
||||
* // }
|
||||
*
|
||||
* i++
|
||||
* // partiallyAppliedSymbol: {
|
||||
* // symbol: `i`
|
||||
* // dispatchReceiver: null
|
||||
* // extensionReceiver: null
|
||||
* // }
|
||||
* // accessType: IncDec {
|
||||
* // kind: INC
|
||||
* // precedence: POSTFIX
|
||||
* // operationSymbol: Int.inc()
|
||||
* // }
|
||||
* }
|
||||
* ```
|
||||
* Note that if the variable has a `<op>Assign` member, then it's represented as a simple `KtFunctionCall`. For example,
|
||||
* ```
|
||||
* fun test(m: MutableList<String>) {
|
||||
* m += "a" // A simple `KtFunctionCall` to `MutableList.plusAssign`, not a `KtVariableAccessCall`. However, the dispatch receiver of this
|
||||
* // call, `m`, is a simple read access represented as a `KtVariableAccessCall`
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
public class KtCompoundVariableAccessCall(
|
||||
private val _partiallyAppliedSymbol: KtPartiallyAppliedVariableSymbol<KtVariableLikeSymbol>,
|
||||
private val _compoundAccess: KtCompoundAccess
|
||||
) : KtVariableAccessCall(), KtCompoundAccessCall {
|
||||
override val token: ValidityToken
|
||||
get() = _partiallyAppliedSymbol.token
|
||||
override val partiallyAppliedSymbol: KtPartiallyAppliedVariableSymbol<KtVariableLikeSymbol> get() = withValidityAssertion { _partiallyAppliedSymbol }
|
||||
override val compoundAccess: KtCompoundAccess get() = withValidityAssertion { _compoundAccess }
|
||||
}
|
||||
|
||||
/**
|
||||
* A compound access using the array access convention. For example,
|
||||
* ```
|
||||
* fun test(m: MutableMap<String, String>) {
|
||||
* m["a"] += "b"
|
||||
* // indexArguments: ["a"]
|
||||
* // getPartiallyAppliedSymbol: {
|
||||
* // symbol: MutableMap.get()
|
||||
* // dispatchReceiver: `m`
|
||||
* // extensionReceiver: null
|
||||
* // }
|
||||
* // setPartiallyAppliedSymbol: {
|
||||
* // symbol: MutableMap.set()
|
||||
* // dispatchReceiver: `m`
|
||||
* // extensionReceiver: null
|
||||
* // }
|
||||
* // accessType: OpAssign {
|
||||
* // kind: PLUS
|
||||
* // operand: "b"
|
||||
* // operationSymbol: String?.plus()
|
||||
* // }
|
||||
* }
|
||||
* ```
|
||||
* Such a call always involve both calls to `get` and `set` functions. With the example above, a call to `String?.plus` is sandwiched
|
||||
* between `get` and `set` call to compute the new value passed to `set`.
|
||||
*
|
||||
* Note that simple access using the array access convention is not captured by this class. For example, assuming `ThrowingMap` throws
|
||||
* in case of absent key instead of returning `null`,
|
||||
* ```
|
||||
* fun test(m: ThrowingMap<String, MutableList<String>>) {
|
||||
* m["a"] += "b"
|
||||
* }
|
||||
* ```
|
||||
* The above call is represented as a simple `KtFunctionCall` to `MutableList.plusAssign`, with the dispatch receiver referencing the
|
||||
* `m["a"]`, which is again a simple `KtFunctionCall` to `ThrowingMap.get`.
|
||||
*/
|
||||
public class KtCompoundArrayAccessCall(
|
||||
private val _compoundAccess: KtCompoundAccess,
|
||||
private val _indexArguments: List<KtExpression>,
|
||||
private val _getPartiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtFunctionSymbol>,
|
||||
private val _setPartiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtFunctionSymbol>,
|
||||
|
||||
) : KtCall(), KtCompoundAccessCall {
|
||||
|
||||
override val token: ValidityToken get() = _compoundAccess.token
|
||||
|
||||
override val compoundAccess: KtCompoundAccess get() = withValidityAssertion { _compoundAccess }
|
||||
|
||||
public val indexArguments: List<KtExpression> get() = withValidityAssertion { _indexArguments }
|
||||
|
||||
/**
|
||||
* The `get` function that's invoked when reading values corresponding to the given [indexArguments].
|
||||
*/
|
||||
public val getPartiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtFunctionSymbol> get() = withValidityAssertion { _getPartiallyAppliedSymbol }
|
||||
|
||||
/**
|
||||
* The `set` function that's invoked when writing values corresponding to the given [indexArguments] and computed value from the
|
||||
* operation.
|
||||
*/
|
||||
public val setPartiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtFunctionSymbol> get() = withValidityAssertion { _setPartiallyAppliedSymbol }
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of access to a variable or using the array access convention.
|
||||
*/
|
||||
public sealed class KtCompoundAccess(private val _operationPartiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtFunctionSymbol>) :
|
||||
ValidityTokenOwner {
|
||||
|
||||
override val token: ValidityToken
|
||||
get() = _operationPartiallyAppliedSymbol.token
|
||||
|
||||
/**
|
||||
* The function that compute the value for this compound access. For example, if the access is `+=`, this is the resolved `plus`
|
||||
* function. If the access is `++`, this is the resolved `inc` function.
|
||||
*/
|
||||
public val operationPartiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtFunctionSymbol> get() = withValidityAssertion { _operationPartiallyAppliedSymbol }
|
||||
|
||||
/**
|
||||
* A compound access that read, compute, and write the computed value back. Note that calls to `<op>Assign` is not represented by this.
|
||||
*/
|
||||
public class CompoundAssign(
|
||||
operationPartiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtFunctionSymbol>,
|
||||
private val _kind: Kind,
|
||||
private val _operand: KtExpression
|
||||
) : KtCompoundAccess(operationPartiallyAppliedSymbol) {
|
||||
public val kind: Kind get() = withValidityAssertion { _kind }
|
||||
public val operand: KtExpression get() = withValidityAssertion { _operand }
|
||||
|
||||
public enum class Kind {
|
||||
PLUS_ASSIGN, MINUS_ASSIGN, TIMES_ASSIGN, DIV_ASSIGN, REM_ASSIGN
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A compound access that read, increment or decrement, and write the computed value back.
|
||||
*/
|
||||
public class IncOrDecOperation(
|
||||
operationPartiallyAppliedSymbol: KtPartiallyAppliedFunctionSymbol<KtFunctionSymbol>,
|
||||
private val _kind: Kind,
|
||||
private val _precedence: Precedence,
|
||||
) : KtCompoundAccess(operationPartiallyAppliedSymbol) {
|
||||
public val kind: Kind get() = withValidityAssertion { _kind }
|
||||
public val precedence: Precedence get() = withValidityAssertion { _precedence }
|
||||
|
||||
public enum class Kind {
|
||||
INC, DEC
|
||||
}
|
||||
|
||||
public enum class Precedence {
|
||||
PREFIX, POSTFIX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A receiver value of a call.
|
||||
*/
|
||||
public sealed class KtReceiverValue : ValidityTokenOwner
|
||||
|
||||
/**
|
||||
* An explicit expression receiver. For example
|
||||
* ```
|
||||
* "".length // explicit receiver `""`
|
||||
* ```
|
||||
*/
|
||||
public class KtExplicitReceiverValue(
|
||||
private val _expression: KtExpression,
|
||||
private val _isSafeNavigation: Boolean,
|
||||
override val token: ValidityToken
|
||||
) : KtReceiverValue() {
|
||||
public val expression: KtExpression get() = withValidityAssertion { _expression }
|
||||
|
||||
/**
|
||||
* Whether safe navigation is used on this receiver. For example
|
||||
* ```
|
||||
* fun test(s1: String?, s2: String) {
|
||||
* s1?.length // explicit receiver `s1` has `isSafeNavigation = true`
|
||||
* s2.length // explicit receiver `s2` has `isSafeNavigation = false`
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
public val isSafeNavigation: Boolean get() = withValidityAssertion { _isSafeNavigation }
|
||||
}
|
||||
|
||||
/**
|
||||
* An implicit receiver. For example
|
||||
* ```
|
||||
* class A {
|
||||
* val i: Int = 1
|
||||
* fun test() {
|
||||
* i // implicit receiver bound to class `A`
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* fun String.test() {
|
||||
* length // implicit receiver bound to the `KtReceiverParameterSymbol` of type `String` declared by `test`.
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
public class KtImplicitReceiverValue(private val _symbol: KtSymbol) : KtReceiverValue() {
|
||||
override val token: ValidityToken get() = _symbol.token
|
||||
public val symbol: KtSymbol get() = withValidityAssertion { _symbol }
|
||||
}
|
||||
|
||||
/**
|
||||
* A smart-casted receiver. For example
|
||||
* ```
|
||||
* fun Any.test() {
|
||||
* if (this is String) {
|
||||
* length // smart-casted implicit receiver bound to the `KtReceiverParameterSymbol` of type `String` declared by `test`.
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
public class KtSmartCastedReceiverValue(private val _original: KtReceiverValue, private val _smartCastType: KtType) : KtReceiverValue() {
|
||||
override val token: ValidityToken
|
||||
get() = _original.token
|
||||
public val original: KtReceiverValue get() = withValidityAssertion { _original }
|
||||
public val smartCastType: KtType get() = withValidityAssertion { _smartCastType }
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public fun KtCallTarget.getSingleCandidateSymbolOrNull(): KtFunctionLikeSymbol?
|
||||
}
|
||||
|
||||
public inline fun <reified S : KtFunctionLikeSymbol> KtCall.isSuccessCallOf(predicate: (S) -> Boolean): Boolean {
|
||||
if (this !is KtFunctionCall) return false
|
||||
if (this !is KtSimpleFunctionCall) return false
|
||||
val symbol = targetFunction.getSuccessCallSymbolOrNull() ?: return false
|
||||
if (symbol !is S) return false
|
||||
return predicate(symbol)
|
||||
|
||||
+11
-27
@@ -5,43 +5,27 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.api.components
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.calls.KtCall
|
||||
import org.jetbrains.kotlin.analysis.api.calls.KtCallInfo
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
public abstract class KtCallResolver : KtAnalysisSessionComponent() {
|
||||
public abstract fun resolveAccessorCall(call: KtSimpleNameExpression): KtCall?
|
||||
public abstract fun resolveCall(call: KtCallElement): KtCall?
|
||||
public abstract fun resolveCall(call: KtBinaryExpression): KtCall?
|
||||
public abstract fun resolveCall(call: KtUnaryExpression): KtCall?
|
||||
public abstract fun resolveCall(call: KtArrayAccessExpression): KtCall?
|
||||
public abstract fun resolveCall(call: KtElement): KtCallInfo?
|
||||
}
|
||||
|
||||
public interface KtCallResolverMixIn : KtAnalysisSessionMixIn {
|
||||
/**
|
||||
* Resolves the given simple name expression to an accessor call if that name refers to a property.
|
||||
*
|
||||
* This spans both Kotlin property and synthetic Java property.
|
||||
*/
|
||||
public fun KtSimpleNameExpression.resolveAccessorCall(): KtCall? =
|
||||
analysisSession.callResolver.resolveAccessorCall(this)
|
||||
|
||||
public fun KtCallElement.resolveCall(): KtCall? =
|
||||
public fun KtElement.resolveCall(): KtCallInfo? =
|
||||
analysisSession.callResolver.resolveCall(this)
|
||||
|
||||
public fun KtBinaryExpression.resolveCall(): KtCall? =
|
||||
analysisSession.callResolver.resolveCall(this)
|
||||
public fun KtCallElement.resolveCall(): KtCallInfo =
|
||||
analysisSession.callResolver.resolveCall(this) ?: error("KtCallElement should always resolve to a KtCallInfo")
|
||||
|
||||
public fun KtUnaryExpression.resolveCall(): KtCall? =
|
||||
analysisSession.callResolver.resolveCall(this)
|
||||
public fun KtBinaryExpression.resolveCall(): KtCallInfo =
|
||||
analysisSession.callResolver.resolveCall(this) ?: error("KtBinaryExpression should always resolve to a KtCallInfo")
|
||||
|
||||
public fun KtArrayAccessExpression.resolveCall(): KtCall? =
|
||||
analysisSession.callResolver.resolveCall(this)
|
||||
public fun KtUnaryExpression.resolveCall(): KtCallInfo =
|
||||
analysisSession.callResolver.resolveCall(this) ?: error("KtUnaryExpression should always resolve to a KtCallInfo")
|
||||
|
||||
public fun KtElement.resolveCallIfPossible(): KtCall? = when (this) {
|
||||
is KtCallElement -> resolveCall()
|
||||
is KtBinaryExpression -> resolveCall()
|
||||
is KtUnaryExpression -> resolveCall()
|
||||
is KtArrayAccessExpression -> resolveCall()
|
||||
else -> null
|
||||
}
|
||||
public fun KtArrayAccessExpression.resolveCall(): KtCallInfo =
|
||||
analysisSession.callResolver.resolveCall(this) ?: error("KtArrayAccessExpression should always resolve to a KtCallInfo")
|
||||
}
|
||||
Reference in New Issue
Block a user