Reformat 'frontend' module according to new codestyle
This commit is contained in:
@@ -22,9 +22,9 @@ import org.jetbrains.kotlin.types.ErrorUtils
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
open class AnalysisResult protected constructor(
|
open class AnalysisResult protected constructor(
|
||||||
val bindingContext: BindingContext,
|
val bindingContext: BindingContext,
|
||||||
val moduleDescriptor: ModuleDescriptor,
|
val moduleDescriptor: ModuleDescriptor,
|
||||||
val shouldGenerateCode: Boolean = true
|
val shouldGenerateCode: Boolean = true
|
||||||
) {
|
) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
@@ -63,33 +63,37 @@ open class AnalysisResult protected constructor(
|
|||||||
private class CompilationError(bindingContext: BindingContext) : AnalysisResult(bindingContext, ErrorUtils.getErrorModule())
|
private class CompilationError(bindingContext: BindingContext) : AnalysisResult(bindingContext, ErrorUtils.getErrorModule())
|
||||||
|
|
||||||
private class InternalError(
|
private class InternalError(
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
val exception: Throwable
|
val exception: Throwable
|
||||||
) : AnalysisResult(bindingContext, ErrorUtils.getErrorModule())
|
) : AnalysisResult(bindingContext, ErrorUtils.getErrorModule())
|
||||||
|
|
||||||
class RetryWithAdditionalJavaRoots(
|
class RetryWithAdditionalJavaRoots(
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
moduleDescriptor: ModuleDescriptor,
|
moduleDescriptor: ModuleDescriptor,
|
||||||
val additionalJavaRoots: List<File>,
|
val additionalJavaRoots: List<File>,
|
||||||
val addToEnvironment: Boolean = true
|
val addToEnvironment: Boolean = true
|
||||||
) : AnalysisResult(bindingContext, moduleDescriptor)
|
) : AnalysisResult(bindingContext, moduleDescriptor)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val EMPTY: AnalysisResult = success(BindingContext.EMPTY, ErrorUtils.getErrorModule())
|
val EMPTY: AnalysisResult = success(BindingContext.EMPTY, ErrorUtils.getErrorModule())
|
||||||
|
|
||||||
@JvmStatic fun success(bindingContext: BindingContext, module: ModuleDescriptor): AnalysisResult {
|
@JvmStatic
|
||||||
|
fun success(bindingContext: BindingContext, module: ModuleDescriptor): AnalysisResult {
|
||||||
return AnalysisResult(bindingContext, module, true)
|
return AnalysisResult(bindingContext, module, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun success(bindingContext: BindingContext, module: ModuleDescriptor, shouldGenerateCode: Boolean): AnalysisResult {
|
@JvmStatic
|
||||||
|
fun success(bindingContext: BindingContext, module: ModuleDescriptor, shouldGenerateCode: Boolean): AnalysisResult {
|
||||||
return AnalysisResult(bindingContext, module, shouldGenerateCode)
|
return AnalysisResult(bindingContext, module, shouldGenerateCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun internalError(bindingContext: BindingContext, error: Throwable): AnalysisResult {
|
@JvmStatic
|
||||||
|
fun internalError(bindingContext: BindingContext, error: Throwable): AnalysisResult {
|
||||||
return InternalError(bindingContext, error)
|
return InternalError(bindingContext, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun compilationError(bindingContext: BindingContext): AnalysisResult {
|
@JvmStatic
|
||||||
|
fun compilationError(bindingContext: BindingContext): AnalysisResult {
|
||||||
return CompilationError(bindingContext)
|
return CompilationError(bindingContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,19 +38,19 @@ interface LeakingThisDescriptor {
|
|||||||
|
|
||||||
data class PropertyIsNull(val property: PropertyDescriptor, override val classOrObject: KtClassOrObject) : LeakingThisDescriptor
|
data class PropertyIsNull(val property: PropertyDescriptor, override val classOrObject: KtClassOrObject) : LeakingThisDescriptor
|
||||||
|
|
||||||
data class NonFinalClass(val klass: ClassDescriptor, override val classOrObject: KtClassOrObject): LeakingThisDescriptor
|
data class NonFinalClass(val klass: ClassDescriptor, override val classOrObject: KtClassOrObject) : LeakingThisDescriptor
|
||||||
|
|
||||||
data class NonFinalProperty(val property: PropertyDescriptor, override val classOrObject: KtClassOrObject): LeakingThisDescriptor
|
data class NonFinalProperty(val property: PropertyDescriptor, override val classOrObject: KtClassOrObject) : LeakingThisDescriptor
|
||||||
|
|
||||||
data class NonFinalFunction(val function: FunctionDescriptor, override val classOrObject: KtClassOrObject): LeakingThisDescriptor
|
data class NonFinalFunction(val function: FunctionDescriptor, override val classOrObject: KtClassOrObject) : LeakingThisDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConstructorConsistencyChecker private constructor(
|
class ConstructorConsistencyChecker private constructor(
|
||||||
private val classOrObject: KtClassOrObject,
|
private val classOrObject: KtClassOrObject,
|
||||||
private val classDescriptor: ClassDescriptor,
|
private val classDescriptor: ClassDescriptor,
|
||||||
private val trace: BindingTrace,
|
private val trace: BindingTrace,
|
||||||
private val pseudocode: Pseudocode,
|
private val pseudocode: Pseudocode,
|
||||||
private val variablesData: PseudocodeVariablesData
|
private val variablesData: PseudocodeVariablesData
|
||||||
) {
|
) {
|
||||||
private val finalClass = classDescriptor.isFinalClass
|
private val finalClass = classDescriptor.isFinalClass
|
||||||
|
|
||||||
@@ -110,77 +110,79 @@ class ConstructorConsistencyChecker private constructor(
|
|||||||
fun check() {
|
fun check() {
|
||||||
// List of properties to initialize
|
// List of properties to initialize
|
||||||
val propertyDescriptors = variablesData.getDeclaredVariables(pseudocode, false)
|
val propertyDescriptors = variablesData.getDeclaredVariables(pseudocode, false)
|
||||||
.filterIsInstance<PropertyDescriptor>()
|
.filterIsInstance<PropertyDescriptor>()
|
||||||
.filter { trace.get(BindingContext.BACKING_FIELD_REQUIRED, it) == true }
|
.filter { trace.get(BindingContext.BACKING_FIELD_REQUIRED, it) == true }
|
||||||
pseudocode.traverse(
|
pseudocode.traverse(
|
||||||
TraversalOrder.FORWARD, variablesData.variableInitializers, { instruction, enterData, _ ->
|
TraversalOrder.FORWARD, variablesData.variableInitializers, { instruction, enterData, _ ->
|
||||||
|
|
||||||
fun firstUninitializedNotNullProperty() = propertyDescriptors.firstOrNull {
|
fun firstUninitializedNotNullProperty() = propertyDescriptors.firstOrNull {
|
||||||
!it.type.isMarkedNullable && !KotlinBuiltIns.isPrimitiveType(it.type) &&
|
!it.type.isMarkedNullable && !KotlinBuiltIns.isPrimitiveType(it.type) &&
|
||||||
!it.isLateInit && !(enterData.getOrNull(it)?.definitelyInitialized() ?: false)
|
!it.isLateInit && !(enterData.getOrNull(it)?.definitelyInitialized() ?: false)
|
||||||
}
|
|
||||||
|
|
||||||
fun handleLeakingThis(expression: KtExpression) {
|
|
||||||
if (!finalClass) {
|
|
||||||
trace.record(BindingContext.LEAKING_THIS, target(expression),
|
|
||||||
LeakingThisDescriptor.NonFinalClass(classDescriptor, classOrObject))
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
val uninitializedProperty = firstUninitializedNotNullProperty()
|
fun handleLeakingThis(expression: KtExpression) {
|
||||||
if (uninitializedProperty != null) {
|
if (!finalClass) {
|
||||||
trace.record(BindingContext.LEAKING_THIS, target(expression),
|
trace.record(
|
||||||
LeakingThisDescriptor.PropertyIsNull(uninitializedProperty, classOrObject))
|
BindingContext.LEAKING_THIS, target(expression),
|
||||||
|
LeakingThisDescriptor.NonFinalClass(classDescriptor, classOrObject)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val uninitializedProperty = firstUninitializedNotNullProperty()
|
||||||
|
if (uninitializedProperty != null) {
|
||||||
|
trace.record(
|
||||||
|
BindingContext.LEAKING_THIS, target(expression),
|
||||||
|
LeakingThisDescriptor.PropertyIsNull(uninitializedProperty, classOrObject)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (instruction.owner != pseudocode) {
|
if (instruction.owner != pseudocode) {
|
||||||
return@traverse
|
return@traverse
|
||||||
}
|
|
||||||
|
|
||||||
if (instruction is KtElementInstruction) {
|
|
||||||
val element = instruction.element
|
|
||||||
when (instruction) {
|
|
||||||
is ReadValueInstruction ->
|
|
||||||
if (element is KtThisExpression) {
|
|
||||||
if (!safeThisUsage(element)) {
|
|
||||||
handleLeakingThis(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is MagicInstruction ->
|
|
||||||
if (instruction.kind == MagicKind.IMPLICIT_RECEIVER) {
|
|
||||||
if (element is KtCallExpression) {
|
|
||||||
if (!safeCallUsage(element)) {
|
|
||||||
handleLeakingThis(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (element is KtReferenceExpression) {
|
|
||||||
if (!safeReferenceUsage(element)) {
|
|
||||||
handleLeakingThis(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
if (instruction is KtElementInstruction) {
|
||||||
|
val element = instruction.element
|
||||||
|
when (instruction) {
|
||||||
|
is ReadValueInstruction ->
|
||||||
|
if (element is KtThisExpression) {
|
||||||
|
if (!safeThisUsage(element)) {
|
||||||
|
handleLeakingThis(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is MagicInstruction ->
|
||||||
|
if (instruction.kind == MagicKind.IMPLICIT_RECEIVER) {
|
||||||
|
if (element is KtCallExpression) {
|
||||||
|
if (!safeCallUsage(element)) {
|
||||||
|
handleLeakingThis(element)
|
||||||
|
}
|
||||||
|
} else if (element is KtReferenceExpression) {
|
||||||
|
if (!safeReferenceUsage(element)) {
|
||||||
|
handleLeakingThis(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun check(
|
fun check(
|
||||||
constructor: KtSecondaryConstructor,
|
constructor: KtSecondaryConstructor,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
pseudocode: Pseudocode,
|
pseudocode: Pseudocode,
|
||||||
pseudocodeVariablesData: PseudocodeVariablesData
|
pseudocodeVariablesData: PseudocodeVariablesData
|
||||||
) = check(constructor.getContainingClassOrObject(), trace, pseudocode, pseudocodeVariablesData)
|
) = check(constructor.getContainingClassOrObject(), trace, pseudocode, pseudocodeVariablesData)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun check(
|
fun check(
|
||||||
classOrObject: KtClassOrObject,
|
classOrObject: KtClassOrObject,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
pseudocode: Pseudocode,
|
pseudocode: Pseudocode,
|
||||||
pseudocodeVariablesData: PseudocodeVariablesData
|
pseudocodeVariablesData: PseudocodeVariablesData
|
||||||
) {
|
) {
|
||||||
val classDescriptor = trace.get(BindingContext.CLASS, classOrObject) ?: return
|
val classDescriptor = trace.get(BindingContext.CLASS, classOrObject) ?: return
|
||||||
ConstructorConsistencyChecker(classOrObject, classDescriptor, trace, pseudocode, pseudocodeVariablesData).check()
|
ConstructorConsistencyChecker(classOrObject, classDescriptor, trace, pseudocode, pseudocodeVariablesData).check()
|
||||||
|
|||||||
@@ -103,25 +103,29 @@ interface ControlFlowBuilder {
|
|||||||
fun loadStringTemplate(expression: KtStringTemplateExpression, inputValues: List<PseudoValue>): InstructionWithValue
|
fun loadStringTemplate(expression: KtStringTemplateExpression, inputValues: List<PseudoValue>): InstructionWithValue
|
||||||
|
|
||||||
fun magic(
|
fun magic(
|
||||||
instructionElement: KtElement,
|
instructionElement: KtElement,
|
||||||
valueElement: KtElement?,
|
valueElement: KtElement?,
|
||||||
inputValues: List<PseudoValue>,
|
inputValues: List<PseudoValue>,
|
||||||
kind: MagicKind): MagicInstruction
|
kind: MagicKind
|
||||||
|
): MagicInstruction
|
||||||
|
|
||||||
fun merge(
|
fun merge(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
inputValues: List<PseudoValue>): MergeInstruction
|
inputValues: List<PseudoValue>
|
||||||
|
): MergeInstruction
|
||||||
|
|
||||||
fun readVariable(
|
fun readVariable(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
resolvedCall: ResolvedCall<*>,
|
resolvedCall: ResolvedCall<*>,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>): ReadValueInstruction
|
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||||
|
): ReadValueInstruction
|
||||||
|
|
||||||
fun call(
|
fun call(
|
||||||
valueElement: KtElement,
|
valueElement: KtElement,
|
||||||
resolvedCall: ResolvedCall<*>,
|
resolvedCall: ResolvedCall<*>,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>,
|
receiverValues: Map<PseudoValue, ReceiverValue>,
|
||||||
arguments: Map<PseudoValue, ValueParameterDescriptor>): CallInstruction
|
arguments: Map<PseudoValue, ValueParameterDescriptor>
|
||||||
|
): CallInstruction
|
||||||
|
|
||||||
enum class PredefinedOperation {
|
enum class PredefinedOperation {
|
||||||
AND,
|
AND,
|
||||||
@@ -130,16 +134,18 @@ interface ControlFlowBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun predefinedOperation(
|
fun predefinedOperation(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
operation: PredefinedOperation,
|
operation: PredefinedOperation,
|
||||||
inputValues: List<PseudoValue>): OperationInstruction
|
inputValues: List<PseudoValue>
|
||||||
|
): OperationInstruction
|
||||||
|
|
||||||
fun read(element: KtElement, target: AccessTarget, receiverValues: Map<PseudoValue, ReceiverValue>): ReadValueInstruction
|
fun read(element: KtElement, target: AccessTarget, receiverValues: Map<PseudoValue, ReceiverValue>): ReadValueInstruction
|
||||||
|
|
||||||
fun write(
|
fun write(
|
||||||
assignment: KtElement,
|
assignment: KtElement,
|
||||||
lValue: KtElement,
|
lValue: KtElement,
|
||||||
rValue: PseudoValue,
|
rValue: PseudoValue,
|
||||||
target: AccessTarget,
|
target: AccessTarget,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>)
|
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
@@ -35,42 +35,46 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun loadConstant(expression: KtExpression, constant: CompileTimeConstant<*>?): InstructionWithValue =
|
override fun loadConstant(expression: KtExpression, constant: CompileTimeConstant<*>?): InstructionWithValue =
|
||||||
delegateBuilder.loadConstant(expression, constant)
|
delegateBuilder.loadConstant(expression, constant)
|
||||||
|
|
||||||
override fun createAnonymousObject(expression: KtObjectLiteralExpression): InstructionWithValue =
|
override fun createAnonymousObject(expression: KtObjectLiteralExpression): InstructionWithValue =
|
||||||
delegateBuilder.createAnonymousObject(expression)
|
delegateBuilder.createAnonymousObject(expression)
|
||||||
|
|
||||||
override fun createLambda(expression: KtFunction): InstructionWithValue = delegateBuilder.createLambda(expression)
|
override fun createLambda(expression: KtFunction): InstructionWithValue = delegateBuilder.createLambda(expression)
|
||||||
|
|
||||||
override fun loadStringTemplate(expression: KtStringTemplateExpression, inputValues: List<PseudoValue>): InstructionWithValue =
|
override fun loadStringTemplate(expression: KtStringTemplateExpression, inputValues: List<PseudoValue>): InstructionWithValue =
|
||||||
delegateBuilder.loadStringTemplate(expression, inputValues)
|
delegateBuilder.loadStringTemplate(expression, inputValues)
|
||||||
|
|
||||||
override fun magic(
|
override fun magic(
|
||||||
instructionElement: KtElement,
|
instructionElement: KtElement,
|
||||||
valueElement: KtElement?,
|
valueElement: KtElement?,
|
||||||
inputValues: List<PseudoValue>,
|
inputValues: List<PseudoValue>,
|
||||||
kind: MagicKind): MagicInstruction = delegateBuilder.magic(instructionElement, valueElement, inputValues, kind)
|
kind: MagicKind
|
||||||
|
): MagicInstruction = delegateBuilder.magic(instructionElement, valueElement, inputValues, kind)
|
||||||
|
|
||||||
override fun merge(expression: KtExpression, inputValues: List<PseudoValue>): MergeInstruction =
|
override fun merge(expression: KtExpression, inputValues: List<PseudoValue>): MergeInstruction =
|
||||||
delegateBuilder.merge(expression, inputValues)
|
delegateBuilder.merge(expression, inputValues)
|
||||||
|
|
||||||
override fun readVariable(
|
override fun readVariable(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
resolvedCall: ResolvedCall<*>,
|
resolvedCall: ResolvedCall<*>,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>): ReadValueInstruction =
|
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||||
delegateBuilder.readVariable(expression, resolvedCall, receiverValues)
|
): ReadValueInstruction =
|
||||||
|
delegateBuilder.readVariable(expression, resolvedCall, receiverValues)
|
||||||
|
|
||||||
override fun call(
|
override fun call(
|
||||||
valueElement: KtElement,
|
valueElement: KtElement,
|
||||||
resolvedCall: ResolvedCall<*>,
|
resolvedCall: ResolvedCall<*>,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>,
|
receiverValues: Map<PseudoValue, ReceiverValue>,
|
||||||
arguments: Map<PseudoValue, ValueParameterDescriptor>): CallInstruction =
|
arguments: Map<PseudoValue, ValueParameterDescriptor>
|
||||||
delegateBuilder.call(valueElement, resolvedCall, receiverValues, arguments)
|
): CallInstruction =
|
||||||
|
delegateBuilder.call(valueElement, resolvedCall, receiverValues, arguments)
|
||||||
|
|
||||||
override fun predefinedOperation(
|
override fun predefinedOperation(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
operation: ControlFlowBuilder.PredefinedOperation,
|
operation: ControlFlowBuilder.PredefinedOperation,
|
||||||
inputValues: List<PseudoValue>): OperationInstruction = delegateBuilder.predefinedOperation(expression, operation, inputValues)
|
inputValues: List<PseudoValue>
|
||||||
|
): OperationInstruction = delegateBuilder.predefinedOperation(expression, operation, inputValues)
|
||||||
|
|
||||||
override fun createUnboundLabel(): Label = delegateBuilder.createUnboundLabel()
|
override fun createUnboundLabel(): Label = delegateBuilder.createUnboundLabel()
|
||||||
|
|
||||||
@@ -140,7 +144,7 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind?): Pseudocode =
|
override fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind?): Pseudocode =
|
||||||
delegateBuilder.exitSubroutine(subroutine, invocationKind)
|
delegateBuilder.exitSubroutine(subroutine, invocationKind)
|
||||||
|
|
||||||
override val currentSubroutine: KtElement
|
override val currentSubroutine: KtElement
|
||||||
get() = delegateBuilder.currentSubroutine
|
get() = delegateBuilder.currentSubroutine
|
||||||
@@ -157,14 +161,15 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun read(element: KtElement, target: AccessTarget, receiverValues: Map<PseudoValue, ReceiverValue>) =
|
override fun read(element: KtElement, target: AccessTarget, receiverValues: Map<PseudoValue, ReceiverValue>) =
|
||||||
delegateBuilder.read(element, target, receiverValues)
|
delegateBuilder.read(element, target, receiverValues)
|
||||||
|
|
||||||
override fun write(
|
override fun write(
|
||||||
assignment: KtElement,
|
assignment: KtElement,
|
||||||
lValue: KtElement,
|
lValue: KtElement,
|
||||||
rValue: PseudoValue,
|
rValue: PseudoValue,
|
||||||
target: AccessTarget,
|
target: AccessTarget,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>) {
|
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||||
|
) {
|
||||||
delegateBuilder.write(assignment, lValue, rValue, target, receiverValues)
|
delegateBuilder.write(assignment, lValue, rValue, target, receiverValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ typealias ImmutableHashMap<K, V> = javaslang.collection.HashMap<K, V>
|
|||||||
|
|
||||||
abstract class ControlFlowInfo<S : ControlFlowInfo<S, D>, D : Any>
|
abstract class ControlFlowInfo<S : ControlFlowInfo<S, D>, D : Any>
|
||||||
internal constructor(
|
internal constructor(
|
||||||
protected val map: ImmutableMap<VariableDescriptor, D> = ImmutableHashMap.empty()
|
protected val map: ImmutableMap<VariableDescriptor, D> = ImmutableHashMap.empty()
|
||||||
) : ImmutableMap<VariableDescriptor, D> by map, ReadOnlyControlFlowInfo<D> {
|
) : ImmutableMap<VariableDescriptor, D> by map, ReadOnlyControlFlowInfo<D> {
|
||||||
abstract protected fun copy(newMap: ImmutableMap<VariableDescriptor, D>): S
|
abstract protected fun copy(newMap: ImmutableMap<VariableDescriptor, D>): S
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ interface ReadOnlyInitControlFlowInfo : ReadOnlyControlFlowInfo<VariableControlF
|
|||||||
typealias ReadOnlyUseControlFlowInfo = ReadOnlyControlFlowInfo<VariableUseState>
|
typealias ReadOnlyUseControlFlowInfo = ReadOnlyControlFlowInfo<VariableUseState>
|
||||||
|
|
||||||
class InitControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableControlFlowState> = ImmutableHashMap.empty()) :
|
class InitControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableControlFlowState> = ImmutableHashMap.empty()) :
|
||||||
ControlFlowInfo<InitControlFlowInfo, VariableControlFlowState>(map), ReadOnlyInitControlFlowInfo {
|
ControlFlowInfo<InitControlFlowInfo, VariableControlFlowState>(map), ReadOnlyInitControlFlowInfo {
|
||||||
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableControlFlowState>) = InitControlFlowInfo(newMap)
|
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableControlFlowState>) = InitControlFlowInfo(newMap)
|
||||||
|
|
||||||
// this = output of EXHAUSTIVE_WHEN_ELSE instruction
|
// this = output of EXHAUSTIVE_WHEN_ELSE instruction
|
||||||
@@ -87,7 +87,7 @@ class InitControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableControlF
|
|||||||
}
|
}
|
||||||
|
|
||||||
class UseControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableUseState> = ImmutableHashMap.empty()) :
|
class UseControlFlowInfo(map: ImmutableMap<VariableDescriptor, VariableUseState> = ImmutableHashMap.empty()) :
|
||||||
ControlFlowInfo<UseControlFlowInfo, VariableUseState>(map), ReadOnlyUseControlFlowInfo {
|
ControlFlowInfo<UseControlFlowInfo, VariableUseState>(map), ReadOnlyUseControlFlowInfo {
|
||||||
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableUseState>) = UseControlFlowInfo(newMap)
|
override fun copy(newMap: ImmutableMap<VariableDescriptor, VariableUseState>) = UseControlFlowInfo(newMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,13 +144,13 @@ class VariableControlFlowState private constructor(val initState: InitState, val
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createInitializedExhaustively(isDeclared: Boolean): VariableControlFlowState =
|
fun createInitializedExhaustively(isDeclared: Boolean): VariableControlFlowState =
|
||||||
create(InitState.INITIALIZED_EXHAUSTIVELY, isDeclared)
|
create(InitState.INITIALIZED_EXHAUSTIVELY, isDeclared)
|
||||||
|
|
||||||
fun create(isInitialized: Boolean, isDeclared: Boolean = false): VariableControlFlowState =
|
fun create(isInitialized: Boolean, isDeclared: Boolean = false): VariableControlFlowState =
|
||||||
create(if (isInitialized) InitState.INITIALIZED else InitState.NOT_INITIALIZED, isDeclared)
|
create(if (isInitialized) InitState.INITIALIZED else InitState.NOT_INITIALIZED, isDeclared)
|
||||||
|
|
||||||
fun create(isDeclaredHere: Boolean, mergedEdgesData: VariableControlFlowState?): VariableControlFlowState =
|
fun create(isDeclaredHere: Boolean, mergedEdgesData: VariableControlFlowState?): VariableControlFlowState =
|
||||||
create(true, isDeclaredHere || mergedEdgesData != null && mergedEdgesData.isDeclared)
|
create(true, isDeclaredHere || mergedEdgesData != null && mergedEdgesData.isDeclared)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+129
-137
@@ -51,11 +51,11 @@ import org.jetbrains.kotlin.types.isFlexible
|
|||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
class ControlFlowInformationProvider private constructor(
|
class ControlFlowInformationProvider private constructor(
|
||||||
private val subroutine: KtElement,
|
private val subroutine: KtElement,
|
||||||
private val trace: BindingTrace,
|
private val trace: BindingTrace,
|
||||||
private val pseudocode: Pseudocode,
|
private val pseudocode: Pseudocode,
|
||||||
private val languageVersionSettings: LanguageVersionSettings,
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
|
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val pseudocodeVariablesData by lazy {
|
private val pseudocodeVariablesData by lazy {
|
||||||
@@ -63,16 +63,16 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
declaration: KtElement,
|
declaration: KtElement,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
diagnosticSuppressor: PlatformDiagnosticSuppressor
|
diagnosticSuppressor: PlatformDiagnosticSuppressor
|
||||||
) : this(
|
) : this(
|
||||||
declaration,
|
declaration,
|
||||||
trace,
|
trace,
|
||||||
ControlFlowProcessor(trace).generatePseudocode(declaration),
|
ControlFlowProcessor(trace).generatePseudocode(declaration),
|
||||||
languageVersionSettings,
|
languageVersionSettings,
|
||||||
diagnosticSuppressor
|
diagnosticSuppressor
|
||||||
)
|
)
|
||||||
|
|
||||||
fun checkForLocalClassOrObjectMode() {
|
fun checkForLocalClassOrObjectMode() {
|
||||||
@@ -161,8 +161,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
override fun visitInstruction(instruction: Instruction) {
|
override fun visitInstruction(instruction: Instruction) {
|
||||||
if (instruction is KtElementInstruction) {
|
if (instruction is KtElementInstruction) {
|
||||||
returnedExpressions.add(instruction.element)
|
returnedExpressions.add(instruction.element)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
throw IllegalStateException("$instruction precedes the exit point")
|
throw IllegalStateException("$instruction precedes the exit point")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,7 +178,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
val expectedType = functionDescriptor?.returnType
|
val expectedType = functionDescriptor?.returnType
|
||||||
|
|
||||||
val providerForLocalDeclaration = ControlFlowInformationProvider(
|
val providerForLocalDeclaration = ControlFlowInformationProvider(
|
||||||
element, trace, localDeclarationInstruction.body, languageVersionSettings, diagnosticSuppressor
|
element, trace, localDeclarationInstruction.body, languageVersionSettings, diagnosticSuppressor
|
||||||
)
|
)
|
||||||
|
|
||||||
providerForLocalDeclaration.checkFunction(expectedType)
|
providerForLocalDeclaration.checkFunction(expectedType)
|
||||||
@@ -189,7 +188,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
|
|
||||||
private fun checkDefiniteReturn(expectedReturnType: KotlinType, unreachableCode: UnreachableCode) {
|
private fun checkDefiniteReturn(expectedReturnType: KotlinType, unreachableCode: UnreachableCode) {
|
||||||
val function = subroutine as? KtDeclarationWithBody
|
val function = subroutine as? KtDeclarationWithBody
|
||||||
?: throw AssertionError("checkDefiniteReturn is called for ${subroutine.text} which is not KtDeclarationWithBody")
|
?: throw AssertionError("checkDefiniteReturn is called for ${subroutine.text} which is not KtDeclarationWithBody")
|
||||||
|
|
||||||
if (!function.hasBody()) return
|
if (!function.hasBody()) return
|
||||||
|
|
||||||
@@ -244,16 +243,15 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
|
|
||||||
if (instruction is JumpInstruction) {
|
if (instruction is JumpInstruction) {
|
||||||
val isJumpElement = element is KtBreakExpression
|
val isJumpElement = element is KtBreakExpression
|
||||||
|| element is KtContinueExpression
|
|| element is KtContinueExpression
|
||||||
|| element is KtReturnExpression
|
|| element is KtReturnExpression
|
||||||
|| element is KtThrowExpression
|
|| element is KtThrowExpression
|
||||||
if (!isJumpElement) continue
|
if (!isJumpElement) continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instruction.dead) {
|
if (instruction.dead) {
|
||||||
unreachableElements.add(element)
|
unreachableElements.add(element)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
reachableElements.add(element)
|
reachableElements.add(element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -274,10 +272,9 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
|
|
||||||
val reportedDiagnosticMap = hashMapOf<Instruction, DiagnosticFactory<*>>()
|
val reportedDiagnosticMap = hashMapOf<Instruction, DiagnosticFactory<*>>()
|
||||||
|
|
||||||
pseudocode.traverse(TraversalOrder.FORWARD, initializers) {
|
pseudocode.traverse(TraversalOrder.FORWARD, initializers) { instruction: Instruction,
|
||||||
instruction: Instruction,
|
enterData: ReadOnlyInitControlFlowInfo,
|
||||||
enterData: ReadOnlyInitControlFlowInfo,
|
exitData: ReadOnlyInitControlFlowInfo ->
|
||||||
exitData: ReadOnlyInitControlFlowInfo ->
|
|
||||||
|
|
||||||
val ctxt = VariableInitContext(instruction, reportedDiagnosticMap, enterData, exitData, blockScopeVariableInfo)
|
val ctxt = VariableInitContext(instruction, reportedDiagnosticMap, enterData, exitData, blockScopeVariableInfo)
|
||||||
if (ctxt.variableDescriptor == null) return@traverse
|
if (ctxt.variableDescriptor == null) return@traverse
|
||||||
@@ -291,8 +288,10 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
if (instruction !is WriteValueInstruction) return@traverse
|
if (instruction !is WriteValueInstruction) return@traverse
|
||||||
val element = instruction.lValue as? KtExpression ?: return@traverse
|
val element = instruction.lValue as? KtExpression ?: return@traverse
|
||||||
var error = checkValReassignment(ctxt, element, instruction,
|
var error = checkValReassignment(
|
||||||
varWithValReassignErrorGenerated)
|
ctxt, element, instruction,
|
||||||
|
varWithValReassignErrorGenerated
|
||||||
|
)
|
||||||
if (!error && processClassOrObject) {
|
if (!error && processClassOrObject) {
|
||||||
error = checkAssignmentBeforeDeclaration(ctxt, element)
|
error = checkAssignmentBeforeDeclaration(ctxt, element)
|
||||||
}
|
}
|
||||||
@@ -319,9 +318,9 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkIsInitialized(
|
private fun checkIsInitialized(
|
||||||
ctxt: VariableInitContext,
|
ctxt: VariableInitContext,
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
varWithUninitializedErrorGenerated: MutableCollection<VariableDescriptor>
|
varWithUninitializedErrorGenerated: MutableCollection<VariableDescriptor>
|
||||||
) {
|
) {
|
||||||
if (element !is KtSimpleNameExpression) return
|
if (element !is KtSimpleNameExpression) return
|
||||||
|
|
||||||
@@ -333,8 +332,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
if (!isDefinitelyInitialized && !varWithUninitializedErrorGenerated.contains(variableDescriptor)) {
|
if (!isDefinitelyInitialized && !varWithUninitializedErrorGenerated.contains(variableDescriptor)) {
|
||||||
if (variableDescriptor !is PropertyDescriptor) {
|
if (variableDescriptor !is PropertyDescriptor) {
|
||||||
variableDescriptor?.let { varWithUninitializedErrorGenerated.add(it) }
|
variableDescriptor?.let { varWithUninitializedErrorGenerated.add(it) }
|
||||||
}
|
} else if (variableDescriptor.isLateInit) {
|
||||||
else if (variableDescriptor.isLateInit) {
|
|
||||||
trace.record(MUST_BE_LATEINIT, variableDescriptor)
|
trace.record(MUST_BE_LATEINIT, variableDescriptor)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -352,7 +350,8 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
report(Errors.UNINITIALIZED_ENUM_COMPANION.on(element, container), ctxt)
|
report(Errors.UNINITIALIZED_ENUM_COMPANION.on(element, container), ctxt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {}
|
else -> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is VariableDescriptor ->
|
is VariableDescriptor ->
|
||||||
@@ -365,8 +364,8 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isCapturedWrite(
|
private fun isCapturedWrite(
|
||||||
variableDescriptor: VariableDescriptor,
|
variableDescriptor: VariableDescriptor,
|
||||||
writeValueInstruction: WriteValueInstruction
|
writeValueInstruction: WriteValueInstruction
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val containingDeclarationDescriptor = variableDescriptor.containingDeclaration
|
val containingDeclarationDescriptor = variableDescriptor.containingDeclaration
|
||||||
// Do not consider top-level properties
|
// Do not consider top-level properties
|
||||||
@@ -405,10 +404,10 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkValReassignment(
|
private fun checkValReassignment(
|
||||||
ctxt: VariableInitContext,
|
ctxt: VariableInitContext,
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
writeValueInstruction: WriteValueInstruction,
|
writeValueInstruction: WriteValueInstruction,
|
||||||
varWithValReassignErrorGenerated: MutableCollection<VariableDescriptor>
|
varWithValReassignErrorGenerated: MutableCollection<VariableDescriptor>
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val variableDescriptor = ctxt.variableDescriptor
|
val variableDescriptor = ctxt.variableDescriptor
|
||||||
val mayBeInitializedNotHere = ctxt.enterInitState?.mayBeInitialized() ?: false
|
val mayBeInitializedNotHere = ctxt.enterInitState?.mayBeInitialized() ?: false
|
||||||
@@ -424,8 +423,12 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
if (Visibilities.isVisible(receiverValue, variableDescriptor, descriptor)
|
if (Visibilities.isVisible(receiverValue, variableDescriptor, descriptor)
|
||||||
&& setterDescriptor != null
|
&& setterDescriptor != null
|
||||||
&& !Visibilities.isVisible(receiverValue, setterDescriptor, descriptor)) {
|
&& !Visibilities.isVisible(receiverValue, setterDescriptor, descriptor)) {
|
||||||
report(Errors.INVISIBLE_SETTER.on(expression, variableDescriptor, setterDescriptor.visibility,
|
report(
|
||||||
setterDescriptor), ctxt)
|
Errors.INVISIBLE_SETTER.on(
|
||||||
|
expression, variableDescriptor, setterDescriptor.visibility,
|
||||||
|
setterDescriptor
|
||||||
|
), ctxt
|
||||||
|
)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -436,11 +439,11 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
var hasReassignMethodReturningUnit = false
|
var hasReassignMethodReturningUnit = false
|
||||||
val parent = expression.parent
|
val parent = expression.parent
|
||||||
val operationReference =
|
val operationReference =
|
||||||
when (parent) {
|
when (parent) {
|
||||||
is KtBinaryExpression -> parent.operationReference
|
is KtBinaryExpression -> parent.operationReference
|
||||||
is KtUnaryExpression -> parent.operationReference
|
is KtUnaryExpression -> parent.operationReference
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
if (operationReference != null) {
|
if (operationReference != null) {
|
||||||
val descriptor = trace.get(BindingContext.REFERENCE_TARGET, operationReference)
|
val descriptor = trace.get(BindingContext.REFERENCE_TARGET, operationReference)
|
||||||
if (descriptor is FunctionDescriptor) {
|
if (descriptor is FunctionDescriptor) {
|
||||||
@@ -462,16 +465,13 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
if (captured && !mayBeInitializedNotHere && hasBackingField && isThisOrNoDispatchReceiver) {
|
if (captured && !mayBeInitializedNotHere && hasBackingField && isThisOrNoDispatchReceiver) {
|
||||||
if (variableDescriptor.containingDeclaration is ClassDescriptor) {
|
if (variableDescriptor.containingDeclaration is ClassDescriptor) {
|
||||||
report(Errors.CAPTURED_MEMBER_VAL_INITIALIZATION.on(expression, variableDescriptor), ctxt)
|
report(Errors.CAPTURED_MEMBER_VAL_INITIALIZATION.on(expression, variableDescriptor), ctxt)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
report(Errors.CAPTURED_VAL_INITIALIZATION.on(expression, variableDescriptor), ctxt)
|
report(Errors.CAPTURED_VAL_INITIALIZATION.on(expression, variableDescriptor), ctxt)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (KtPsiUtil.isBackingFieldReference(variableDescriptor)) {
|
if (KtPsiUtil.isBackingFieldReference(variableDescriptor)) {
|
||||||
reportValReassigned(expression, variableDescriptor, ctxt)
|
reportValReassigned(expression, variableDescriptor, ctxt)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor), ctxt)
|
report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor), ctxt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -497,21 +497,20 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkAssignmentBeforeDeclaration(ctxt: VariableInitContext, expression: KtExpression) =
|
private fun checkAssignmentBeforeDeclaration(ctxt: VariableInitContext, expression: KtExpression) =
|
||||||
if (ctxt.isInitializationBeforeDeclaration()) {
|
if (ctxt.isInitializationBeforeDeclaration()) {
|
||||||
if (ctxt.variableDescriptor != null) {
|
if (ctxt.variableDescriptor != null) {
|
||||||
report(Errors.INITIALIZATION_BEFORE_DECLARATION.on(expression, ctxt.variableDescriptor), ctxt)
|
report(Errors.INITIALIZATION_BEFORE_DECLARATION.on(expression, ctxt.variableDescriptor), ctxt)
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
private fun VariableInitContext.isInitializationBeforeDeclaration(): Boolean =
|
private fun VariableInitContext.isInitializationBeforeDeclaration(): Boolean =
|
||||||
// is not declared
|
// is not declared
|
||||||
enterInitState?.isDeclared != true && exitInitState?.isDeclared != true &&
|
enterInitState?.isDeclared != true && exitInitState?.isDeclared != true &&
|
||||||
// wasn't initialized before current instruction
|
// wasn't initialized before current instruction
|
||||||
enterInitState?.mayBeInitialized() != true
|
enterInitState?.mayBeInitialized() != true
|
||||||
|
|
||||||
private fun checkInitializationForCustomSetter(ctxt: VariableInitContext, expression: KtExpression): Boolean {
|
private fun checkInitializationForCustomSetter(ctxt: VariableInitContext, expression: KtExpression): Boolean {
|
||||||
val variableDescriptor = ctxt.variableDescriptor
|
val variableDescriptor = ctxt.variableDescriptor
|
||||||
@@ -524,17 +523,16 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val property = DescriptorToSourceUtils.descriptorToDeclaration(variableDescriptor) as? KtProperty
|
val property = DescriptorToSourceUtils.descriptorToDeclaration(variableDescriptor) as? KtProperty
|
||||||
?: throw AssertionError("$variableDescriptor is not related to KtProperty")
|
?: throw AssertionError("$variableDescriptor is not related to KtProperty")
|
||||||
val setter = property.setter
|
val setter = property.setter
|
||||||
if (variableDescriptor.modality == Modality.FINAL && (setter == null || !setter.hasBody())) {
|
if (variableDescriptor.modality == Modality.FINAL && (setter == null || !setter.hasBody())) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val variable = if (expression is KtDotQualifiedExpression &&
|
val variable = if (expression is KtDotQualifiedExpression &&
|
||||||
expression.receiverExpression is KtThisExpression) {
|
expression.receiverExpression is KtThisExpression) {
|
||||||
expression.selectorExpression
|
expression.selectorExpression
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
expression
|
expression
|
||||||
}
|
}
|
||||||
if (variable is KtSimpleNameExpression) {
|
if (variable is KtSimpleNameExpression) {
|
||||||
@@ -545,8 +543,8 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun recordInitializedVariables(
|
private fun recordInitializedVariables(
|
||||||
pseudocode: Pseudocode,
|
pseudocode: Pseudocode,
|
||||||
initializersMap: Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>>
|
initializersMap: Map<Instruction, Edges<ReadOnlyInitControlFlowInfo>>
|
||||||
) {
|
) {
|
||||||
val initializers = initializersMap[pseudocode.exitInstruction] ?: return
|
val initializers = initializersMap[pseudocode.exitInstruction] ?: return
|
||||||
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, false)
|
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, false)
|
||||||
@@ -566,15 +564,15 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
val reportedDiagnosticMap = hashMapOf<Instruction, DiagnosticFactory<*>>()
|
val reportedDiagnosticMap = hashMapOf<Instruction, DiagnosticFactory<*>>()
|
||||||
val unusedValueExpressions = hashMapOf<KtExpression, Pair<VariableDescriptor, VariableUseContext>>()
|
val unusedValueExpressions = hashMapOf<KtExpression, Pair<VariableDescriptor, VariableUseContext>>()
|
||||||
val usedValueExpressions = hashSetOf<KtExpression>()
|
val usedValueExpressions = hashSetOf<KtExpression>()
|
||||||
pseudocode.traverse(TraversalOrder.BACKWARD, variableStatusData) {
|
pseudocode.traverse(TraversalOrder.BACKWARD, variableStatusData) { instruction: Instruction,
|
||||||
instruction: Instruction,
|
enterData: ReadOnlyUseControlFlowInfo,
|
||||||
enterData: ReadOnlyUseControlFlowInfo,
|
_: ReadOnlyUseControlFlowInfo ->
|
||||||
_: ReadOnlyUseControlFlowInfo ->
|
|
||||||
|
|
||||||
val ctxt = VariableUseContext(instruction, reportedDiagnosticMap)
|
val ctxt = VariableUseContext(instruction, reportedDiagnosticMap)
|
||||||
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.owner, false)
|
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.owner, false)
|
||||||
val variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(
|
val variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(
|
||||||
instruction, trace.bindingContext)
|
instruction, trace.bindingContext
|
||||||
|
)
|
||||||
if (variableDescriptor == null
|
if (variableDescriptor == null
|
||||||
|| !declaredVariables.contains(variableDescriptor)
|
|| !declaredVariables.contains(variableDescriptor)
|
||||||
|| !ExpressionTypingUtils.isLocal(variableDescriptor.containingDeclaration, variableDescriptor)) {
|
|| !ExpressionTypingUtils.isLocal(variableDescriptor.containingDeclaration, variableDescriptor)) {
|
||||||
@@ -587,8 +585,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
val expressionInQuestion = instruction.element as? KtExpression ?: return@traverse
|
val expressionInQuestion = instruction.element as? KtExpression ?: return@traverse
|
||||||
if (variableUseState != READ) {
|
if (variableUseState != READ) {
|
||||||
unusedValueExpressions.put(expressionInQuestion, variableDescriptor to ctxt)
|
unusedValueExpressions.put(expressionInQuestion, variableDescriptor to ctxt)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
usedValueExpressions.add(expressionInQuestion)
|
usedValueExpressions.add(expressionInQuestion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -618,10 +615,10 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun processUnusedDeclaration(
|
private fun processUnusedDeclaration(
|
||||||
element: KtNamedDeclaration,
|
element: KtNamedDeclaration,
|
||||||
variableDescriptor: VariableDescriptor,
|
variableDescriptor: VariableDescriptor,
|
||||||
ctxt: VariableUseContext,
|
ctxt: VariableUseContext,
|
||||||
variableUseState: VariableUseState?
|
variableUseState: VariableUseState?
|
||||||
) {
|
) {
|
||||||
element.nameIdentifier ?: return
|
element.nameIdentifier ?: return
|
||||||
if (!VariableUseState.isUsed(variableUseState)) {
|
if (!VariableUseState.isUsed(variableUseState)) {
|
||||||
@@ -637,11 +634,9 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
element is KtParameter ->
|
element is KtParameter ->
|
||||||
processUnusedParameter(ctxt, element, variableDescriptor)
|
processUnusedParameter(ctxt, element, variableDescriptor)
|
||||||
}
|
}
|
||||||
}
|
} else if (variableUseState === ONLY_WRITTEN_NEVER_READ && KtPsiUtil.isRemovableVariableDeclaration(element)) {
|
||||||
else if (variableUseState === ONLY_WRITTEN_NEVER_READ && KtPsiUtil.isRemovableVariableDeclaration(element)) {
|
|
||||||
report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on(element, variableDescriptor), ctxt)
|
report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on(element, variableDescriptor), ctxt)
|
||||||
}
|
} else if (variableUseState === WRITTEN_AFTER_READ && element is KtVariableDeclaration) {
|
||||||
else if (variableUseState === WRITTEN_AFTER_READ && element is KtVariableDeclaration) {
|
|
||||||
when (element) {
|
when (element) {
|
||||||
is KtProperty ->
|
is KtProperty ->
|
||||||
element.initializer?.let {
|
element.initializer?.let {
|
||||||
@@ -675,8 +670,8 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
val mainFunctionDetector = MainFunctionDetector(trace.bindingContext)
|
val mainFunctionDetector = MainFunctionDetector(trace.bindingContext)
|
||||||
val isMain = owner is KtNamedFunction && mainFunctionDetector.isMain(owner)
|
val isMain = owner is KtNamedFunction && mainFunctionDetector.isMain(owner)
|
||||||
val functionDescriptor =
|
val functionDescriptor =
|
||||||
trace.get(DECLARATION_TO_DESCRIPTOR, owner) as? FunctionDescriptor
|
trace.get(DECLARATION_TO_DESCRIPTOR, owner) as? FunctionDescriptor
|
||||||
?: throw AssertionError(owner.text)
|
?: throw AssertionError(owner.text)
|
||||||
val functionName = functionDescriptor.name
|
val functionName = functionDescriptor.name
|
||||||
if (isMain
|
if (isMain
|
||||||
|| functionDescriptor.isOverridableOrOverrides
|
|| functionDescriptor.isOverridableOrOverrides
|
||||||
@@ -691,8 +686,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
if (anonymous) {
|
if (anonymous) {
|
||||||
report(UNUSED_ANONYMOUS_PARAMETER.on(element, variableDescriptor), ctxt)
|
report(UNUSED_ANONYMOUS_PARAMETER.on(element, variableDescriptor), ctxt)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
report(UNUSED_PARAMETER.on(element, variableDescriptor), ctxt)
|
report(UNUSED_PARAMETER.on(element, variableDescriptor), ctxt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -711,10 +705,12 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
|
|
||||||
if (element.isUsedAsStatement(trace.bindingContext) && instruction.sideEffectFree) {
|
if (element.isUsedAsStatement(trace.bindingContext) && instruction.sideEffectFree) {
|
||||||
val context = VariableContext(instruction, reportedDiagnosticMap)
|
val context = VariableContext(instruction, reportedDiagnosticMap)
|
||||||
report(when (element) {
|
report(
|
||||||
is KtLambdaExpression -> Errors.UNUSED_LAMBDA_EXPRESSION.on(element)
|
when (element) {
|
||||||
else -> Errors.UNUSED_EXPRESSION.on(element)
|
is KtLambdaExpression -> Errors.UNUSED_LAMBDA_EXPRESSION.on(element)
|
||||||
}, context)
|
else -> Errors.UNUSED_EXPRESSION.on(element)
|
||||||
|
}, context
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -745,8 +741,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
|
|
||||||
if (thenExpression == null || elseExpression == null) {
|
if (thenExpression == null || elseExpression == null) {
|
||||||
trace.report(INVALID_IF_AS_EXPRESSION.on(element.ifKeyword))
|
trace.report(INVALID_IF_AS_EXPRESSION.on(element.ifKeyword))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
checkImplicitCastOnConditionalExpression(element)
|
checkImplicitCastOnConditionalExpression(element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -811,8 +806,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
if (usedAsExpression && missingCases.isNotEmpty()) {
|
if (usedAsExpression && missingCases.isNotEmpty()) {
|
||||||
if (elseEntry != null) continue
|
if (elseEntry != null) continue
|
||||||
trace.report(NO_ELSE_IN_WHEN.on(element, missingCases))
|
trace.report(NO_ELSE_IN_WHEN.on(element, missingCases))
|
||||||
}
|
} else if (subjectExpression != null) {
|
||||||
else if (subjectExpression != null) {
|
|
||||||
val subjectType = trace.getType(subjectExpression)
|
val subjectType = trace.getType(subjectExpression)
|
||||||
if (elseEntry != null) {
|
if (elseEntry != null) {
|
||||||
if (missingCases.isEmpty() && subjectType != null && !subjectType.isFlexible()) {
|
if (missingCases.isEmpty() && subjectType != null && !subjectType.isFlexible()) {
|
||||||
@@ -923,17 +917,17 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isInsideTry(element: KtElement) =
|
private fun isInsideTry(element: KtElement) =
|
||||||
getParentOfType(
|
getParentOfType(
|
||||||
element,
|
element,
|
||||||
KtTryExpression::class.java, KtFunction::class.java, KtAnonymousInitializer::class.java
|
KtTryExpression::class.java, KtFunction::class.java, KtAnonymousInitializer::class.java
|
||||||
) is KtTryExpression
|
) is KtTryExpression
|
||||||
|
|
||||||
private fun CallInstruction.isTailCall(subroutine: KtElement = this@ControlFlowInformationProvider.subroutine): Boolean {
|
private fun CallInstruction.isTailCall(subroutine: KtElement = this@ControlFlowInformationProvider.subroutine): Boolean {
|
||||||
val tailInstructionDetector = TailInstructionDetector(subroutine)
|
val tailInstructionDetector = TailInstructionDetector(subroutine)
|
||||||
return traverseFollowingInstructions(
|
return traverseFollowingInstructions(
|
||||||
this,
|
this,
|
||||||
hashSetOf(),
|
hashSetOf(),
|
||||||
TraversalOrder.FORWARD
|
TraversalOrder.FORWARD
|
||||||
) {
|
) {
|
||||||
if (it == this@isTailCall || it.accept(tailInstructionDetector))
|
if (it == this@isTailCall || it.accept(tailInstructionDetector))
|
||||||
TraverseInstructionResult.CONTINUE
|
TraverseInstructionResult.CONTINUE
|
||||||
@@ -957,8 +951,8 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
* (depends on whether it should be reported for all or only for one of the copies)
|
* (depends on whether it should be reported for all or only for one of the copies)
|
||||||
*/
|
*/
|
||||||
private fun report(
|
private fun report(
|
||||||
diagnostic: Diagnostic,
|
diagnostic: Diagnostic,
|
||||||
ctxt: VariableContext
|
ctxt: VariableContext
|
||||||
) {
|
) {
|
||||||
val instruction = ctxt.instruction
|
val instruction = ctxt.instruction
|
||||||
if (instruction.copies.isEmpty()) {
|
if (instruction.copies.isEmpty()) {
|
||||||
@@ -985,8 +979,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
if (sameErrorForAllCopies) {
|
if (sameErrorForAllCopies) {
|
||||||
trace.report(diagnostic)
|
trace.report(diagnostic)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
//only one reporting required
|
//only one reporting required
|
||||||
if (!alreadyReported) {
|
if (!alreadyReported) {
|
||||||
trace.report(diagnostic)
|
trace.report(diagnostic)
|
||||||
@@ -996,26 +989,26 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
|
|
||||||
|
|
||||||
private open inner class VariableContext(
|
private open inner class VariableContext(
|
||||||
internal val instruction: Instruction,
|
internal val instruction: Instruction,
|
||||||
internal val reportedDiagnosticMap: MutableMap<Instruction, DiagnosticFactory<*>>
|
internal val reportedDiagnosticMap: MutableMap<Instruction, DiagnosticFactory<*>>
|
||||||
) {
|
) {
|
||||||
internal val variableDescriptor = PseudocodeUtil.extractVariableDescriptorFromReference(instruction, trace.bindingContext)
|
internal val variableDescriptor = PseudocodeUtil.extractVariableDescriptorFromReference(instruction, trace.bindingContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class VariableInitContext(
|
private inner class VariableInitContext(
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
map: MutableMap<Instruction, DiagnosticFactory<*>>,
|
map: MutableMap<Instruction, DiagnosticFactory<*>>,
|
||||||
`in`: ReadOnlyInitControlFlowInfo,
|
`in`: ReadOnlyInitControlFlowInfo,
|
||||||
out: ReadOnlyInitControlFlowInfo,
|
out: ReadOnlyInitControlFlowInfo,
|
||||||
blockScopeVariableInfo: BlockScopeVariableInfo
|
blockScopeVariableInfo: BlockScopeVariableInfo
|
||||||
) : VariableContext(instruction, map) {
|
) : VariableContext(instruction, map) {
|
||||||
internal val enterInitState = initialize(variableDescriptor, blockScopeVariableInfo, `in`)
|
internal val enterInitState = initialize(variableDescriptor, blockScopeVariableInfo, `in`)
|
||||||
internal val exitInitState = initialize(variableDescriptor, blockScopeVariableInfo, out)
|
internal val exitInitState = initialize(variableDescriptor, blockScopeVariableInfo, out)
|
||||||
|
|
||||||
private fun initialize(
|
private fun initialize(
|
||||||
variableDescriptor: VariableDescriptor?,
|
variableDescriptor: VariableDescriptor?,
|
||||||
blockScopeVariableInfo: BlockScopeVariableInfo,
|
blockScopeVariableInfo: BlockScopeVariableInfo,
|
||||||
map: ReadOnlyInitControlFlowInfo
|
map: ReadOnlyInitControlFlowInfo
|
||||||
): VariableControlFlowState? {
|
): VariableControlFlowState? {
|
||||||
val state = map.getOrNull(variableDescriptor ?: return null)
|
val state = map.getOrNull(variableDescriptor ?: return null)
|
||||||
if (state != null) return state
|
if (state != null) return state
|
||||||
@@ -1024,26 +1017,27 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class VariableUseContext(
|
private inner class VariableUseContext(
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
map: MutableMap<Instruction, DiagnosticFactory<*>>
|
map: MutableMap<Instruction, DiagnosticFactory<*>>
|
||||||
) : VariableContext(instruction, map)
|
) : VariableContext(instruction, map)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
// Should return KtDeclarationWithBody, KtClassOrObject, or KtClassInitializer
|
// Should return KtDeclarationWithBody, KtClassOrObject, or KtClassInitializer
|
||||||
fun getElementParentDeclaration(element: KtElement) =
|
fun getElementParentDeclaration(element: KtElement) =
|
||||||
getParentOfType(element, KtDeclarationWithBody::class.java, KtClassOrObject::class.java, KtClassInitializer::class.java)
|
getParentOfType(element, KtDeclarationWithBody::class.java, KtClassOrObject::class.java, KtClassInitializer::class.java)
|
||||||
|
|
||||||
fun getDeclarationDescriptorIncludingConstructors(context: BindingContext, declaration: KtDeclaration?): DeclarationDescriptor? {
|
fun getDeclarationDescriptorIncludingConstructors(context: BindingContext, declaration: KtDeclaration?): DeclarationDescriptor? {
|
||||||
val descriptor = context.get(DECLARATION_TO_DESCRIPTOR,
|
val descriptor = context.get(
|
||||||
(declaration as? KtClassInitializer)?.containingDeclaration ?: declaration)
|
DECLARATION_TO_DESCRIPTOR,
|
||||||
|
(declaration as? KtClassInitializer)?.containingDeclaration ?: declaration
|
||||||
|
)
|
||||||
return if (descriptor is ClassDescriptor && declaration is KtClassInitializer) {
|
return if (descriptor is ClassDescriptor && declaration is KtClassInitializer) {
|
||||||
// For a class primary constructor, we cannot directly get ConstructorDescriptor by KtClassInitializer,
|
// For a class primary constructor, we cannot directly get ConstructorDescriptor by KtClassInitializer,
|
||||||
// so we have to do additional conversion: KtClassInitializer -> KtClassOrObject -> ClassDescriptor -> ConstructorDescriptor
|
// so we have to do additional conversion: KtClassInitializer -> KtClassOrObject -> ClassDescriptor -> ConstructorDescriptor
|
||||||
descriptor.unsubstitutedPrimaryConstructor
|
descriptor.unsubstitutedPrimaryConstructor
|
||||||
?: (descriptor as? ClassDescriptorWithResolutionScopes)?.scopeForInitializerResolution?.ownerDescriptor
|
?: (descriptor as? ClassDescriptorWithResolutionScopes)?.scopeForInitializerResolution?.ownerDescriptor
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
descriptor
|
descriptor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1069,8 +1063,8 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun collectResultingExpressionsOfConditionalExpressionRec(
|
private fun collectResultingExpressionsOfConditionalExpressionRec(
|
||||||
expression: KtExpression?,
|
expression: KtExpression?,
|
||||||
resultingExpressions: MutableList<KtExpression>
|
resultingExpressions: MutableList<KtExpression>
|
||||||
) {
|
) {
|
||||||
when (expression) {
|
when (expression) {
|
||||||
is KtIfExpression -> {
|
is KtIfExpression -> {
|
||||||
@@ -1084,8 +1078,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
val resultingExpression = getResultingExpression(expression)
|
val resultingExpression = getResultingExpression(expression)
|
||||||
if (resultingExpression is KtIfExpression || resultingExpression is KtWhenExpression) {
|
if (resultingExpression is KtIfExpression || resultingExpression is KtWhenExpression) {
|
||||||
collectResultingExpressionsOfConditionalExpressionRec(resultingExpression, resultingExpressions)
|
collectResultingExpressionsOfConditionalExpressionRec(resultingExpression, resultingExpressions)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
resultingExpressions.add(resultingExpression)
|
resultingExpressions.add(resultingExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1106,8 +1099,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
private fun combineKinds(kind: TailRecursionKind, existingKind: TailRecursionKind?): TailRecursionKind {
|
private fun combineKinds(kind: TailRecursionKind, existingKind: TailRecursionKind?): TailRecursionKind {
|
||||||
return if (existingKind == null || existingKind == kind) {
|
return if (existingKind == null || existingKind == kind) {
|
||||||
kind
|
kind
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
when {
|
when {
|
||||||
check(kind, existingKind, IN_TRY, TAIL_CALL) -> IN_TRY
|
check(kind, existingKind, IN_TRY, TAIL_CALL) -> IN_TRY
|
||||||
check(kind, existingKind, IN_TRY, NON_TAIL) -> IN_TRY
|
check(kind, existingKind, IN_TRY, NON_TAIL) -> IN_TRY
|
||||||
@@ -1119,9 +1111,9 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
private fun check(a: Any, b: Any, x: Any, y: Any) = a === x && b === y || a === y && b === x
|
private fun check(a: Any, b: Any, x: Any, y: Any) = a === x && b === y || a === y && b === x
|
||||||
|
|
||||||
private fun mustBeReportedOnAllCopies(diagnosticFactory: DiagnosticFactory<*>) =
|
private fun mustBeReportedOnAllCopies(diagnosticFactory: DiagnosticFactory<*>) =
|
||||||
diagnosticFactory === UNUSED_VARIABLE
|
diagnosticFactory === UNUSED_VARIABLE
|
||||||
|| diagnosticFactory === UNUSED_PARAMETER
|
|| diagnosticFactory === UNUSED_PARAMETER
|
||||||
|| diagnosticFactory === UNUSED_ANONYMOUS_PARAMETER
|
|| diagnosticFactory === UNUSED_ANONYMOUS_PARAMETER
|
||||||
|| diagnosticFactory === UNUSED_CHANGED_VALUE
|
|| diagnosticFactory === UNUSED_CHANGED_VALUE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,8 +88,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
generateImplicitReturnValue(bodyExpression, subroutine)
|
generateImplicitReturnValue(bodyExpression, subroutine)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
cfpVisitor.generateInstructions(subroutine)
|
cfpVisitor.generateInstructions(subroutine)
|
||||||
}
|
}
|
||||||
return builder.exitSubroutine(subroutine, invocationKind)
|
return builder.exitSubroutine(subroutine, invocationKind)
|
||||||
@@ -130,7 +129,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
private val conditionVisitor = object : KtVisitorVoid() {
|
private val conditionVisitor = object : KtVisitorVoid() {
|
||||||
|
|
||||||
private fun getSubjectExpression(condition: KtWhenCondition): KtExpression? =
|
private fun getSubjectExpression(condition: KtWhenCondition): KtExpression? =
|
||||||
condition.getStrictParentOfType<KtWhenExpression>()?.subjectExpression
|
condition.getStrictParentOfType<KtWhenExpression>()?.subjectExpression
|
||||||
|
|
||||||
override fun visitWhenConditionInRange(condition: KtWhenConditionInRange) {
|
override fun visitWhenConditionInRange(condition: KtWhenConditionInRange) {
|
||||||
if (!generateCall(condition.operationReference)) {
|
if (!generateCall(condition.operationReference)) {
|
||||||
@@ -155,8 +154,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
if (subjectExpression != null) {
|
if (subjectExpression != null) {
|
||||||
// todo: this can be replaced by equals() invocation (when corresponding resolved call is recorded)
|
// todo: this can be replaced by equals() invocation (when corresponding resolved call is recorded)
|
||||||
createNonSyntheticValue(condition, MagicKind.EQUALS_IN_WHEN_CONDITION, subjectExpression, expression)
|
createNonSyntheticValue(condition, MagicKind.EQUALS_IN_WHEN_CONDITION, subjectExpression, expression)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
copyValue(expression, condition)
|
copyValue(expression, condition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,13 +191,13 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createSyntheticValue(instructionElement: KtElement, kind: MagicKind, vararg from: KtElement): PseudoValue =
|
private fun createSyntheticValue(instructionElement: KtElement, kind: MagicKind, vararg from: KtElement): PseudoValue =
|
||||||
builder.magic(instructionElement, null, elementsToValues(from.asList()), kind).outputValue
|
builder.magic(instructionElement, null, elementsToValues(from.asList()), kind).outputValue
|
||||||
|
|
||||||
private fun createNonSyntheticValue(to: KtElement, from: List<KtElement?>, kind: MagicKind): PseudoValue =
|
private fun createNonSyntheticValue(to: KtElement, from: List<KtElement?>, kind: MagicKind): PseudoValue =
|
||||||
builder.magic(to, to, elementsToValues(from), kind).outputValue
|
builder.magic(to, to, elementsToValues(from), kind).outputValue
|
||||||
|
|
||||||
private fun createNonSyntheticValue(to: KtElement, kind: MagicKind, vararg from: KtElement?): PseudoValue =
|
private fun createNonSyntheticValue(to: KtElement, kind: MagicKind, vararg from: KtElement?): PseudoValue =
|
||||||
createNonSyntheticValue(to, from.asList(), kind)
|
createNonSyntheticValue(to, from.asList(), kind)
|
||||||
|
|
||||||
private fun mergeValues(from: List<KtExpression>, to: KtExpression) {
|
private fun mergeValues(from: List<KtExpression>, to: KtExpression) {
|
||||||
builder.merge(to, elementsToValues(from))
|
builder.merge(to, elementsToValues(from))
|
||||||
@@ -217,14 +215,14 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun elementsToValues(from: List<KtElement?>): List<PseudoValue> =
|
private fun elementsToValues(from: List<KtElement?>): List<PseudoValue> =
|
||||||
from.mapNotNull { element -> getBoundOrUnreachableValue(element) }
|
from.mapNotNull { element -> getBoundOrUnreachableValue(element) }
|
||||||
|
|
||||||
private fun generateInitializer(declaration: KtDeclaration, initValue: PseudoValue) {
|
private fun generateInitializer(declaration: KtDeclaration, initValue: PseudoValue) {
|
||||||
builder.write(declaration, declaration, initValue, getDeclarationAccessTarget(declaration), emptyMap())
|
builder.write(declaration, declaration, initValue, getDeclarationAccessTarget(declaration), emptyMap())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getResolvedCallAccessTarget(element: KtElement?): AccessTarget =
|
private fun getResolvedCallAccessTarget(element: KtElement?): AccessTarget =
|
||||||
element.getResolvedCall(trace.bindingContext)?.let { AccessTarget.Call(it) }
|
element.getResolvedCall(trace.bindingContext)?.let { AccessTarget.Call(it) }
|
||||||
?: AccessTarget.BlackBox
|
?: AccessTarget.BlackBox
|
||||||
|
|
||||||
private fun getDeclarationAccessTarget(element: KtElement): AccessTarget {
|
private fun getDeclarationAccessTarget(element: KtElement): AccessTarget {
|
||||||
@@ -276,8 +274,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
val resolvedCall = expression.getResolvedCall(trace.bindingContext)
|
val resolvedCall = expression.getResolvedCall(trace.bindingContext)
|
||||||
if (resolvedCall is VariableAsFunctionResolvedCall) {
|
if (resolvedCall is VariableAsFunctionResolvedCall) {
|
||||||
generateCall(resolvedCall.variableCall)
|
generateCall(resolvedCall.variableCall)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (resolvedCall == null) {
|
if (resolvedCall == null) {
|
||||||
val qualifier = trace.bindingContext[BindingContext.QUALIFIER, expression]
|
val qualifier = trace.bindingContext[BindingContext.QUALIFIER, expression]
|
||||||
if (qualifier != null && generateQualifier(expression, qualifier)) return
|
if (qualifier != null && generateQualifier(expression, qualifier)) return
|
||||||
@@ -305,11 +302,9 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
val right = expression.right
|
val right = expression.right
|
||||||
if (operationType === ANDAND || operationType === OROR) {
|
if (operationType === ANDAND || operationType === OROR) {
|
||||||
generateBooleanOperation(expression)
|
generateBooleanOperation(expression)
|
||||||
}
|
} else if (operationType === EQ) {
|
||||||
else if (operationType === EQ) {
|
|
||||||
visitAssignment(left, getDeferredValue(right), expression)
|
visitAssignment(left, getDeferredValue(right), expression)
|
||||||
}
|
} else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
|
||||||
else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
|
|
||||||
val resolvedCall = expression.getResolvedCall(trace.bindingContext)
|
val resolvedCall = expression.getResolvedCall(trace.bindingContext)
|
||||||
if (resolvedCall != null) {
|
if (resolvedCall != null) {
|
||||||
val rhsValue = generateCall(resolvedCall).outputValue
|
val rhsValue = generateCall(resolvedCall).outputValue
|
||||||
@@ -321,12 +316,10 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
*/
|
*/
|
||||||
visitAssignment(left, getValueAsFunction(rhsValue), expression)
|
visitAssignment(left, getValueAsFunction(rhsValue), expression)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
generateBothArgumentsAndMark(expression)
|
generateBothArgumentsAndMark(expression)
|
||||||
}
|
}
|
||||||
}
|
} else if (operationType === ELVIS) {
|
||||||
else if (operationType === ELVIS) {
|
|
||||||
generateInstructions(left)
|
generateInstructions(left)
|
||||||
mark(expression)
|
mark(expression)
|
||||||
val afterElvis = builder.createUnboundLabel("after elvis operator")
|
val afterElvis = builder.createUnboundLabel("after elvis operator")
|
||||||
@@ -334,8 +327,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
generateInstructions(right)
|
generateInstructions(right)
|
||||||
builder.bindLabel(afterElvis)
|
builder.bindLabel(afterElvis)
|
||||||
mergeValues(listOf(left, right).filterNotNull(), expression)
|
mergeValues(listOf(left, right).filterNotNull(), expression)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (!generateCall(expression)) {
|
if (!generateCall(expression)) {
|
||||||
generateBothArgumentsAndMark(expression)
|
generateBothArgumentsAndMark(expression)
|
||||||
}
|
}
|
||||||
@@ -351,8 +343,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
generateInstructions(left)
|
generateInstructions(left)
|
||||||
if (operationType === ANDAND) {
|
if (operationType === ANDAND) {
|
||||||
builder.jumpOnFalse(resultLabel, expression, builder.getBoundValue(left))
|
builder.jumpOnFalse(resultLabel, expression, builder.getBoundValue(left))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
builder.jumpOnTrue(resultLabel, expression, builder.getBoundValue(left))
|
builder.jumpOnTrue(resultLabel, expression, builder.getBoundValue(left))
|
||||||
}
|
}
|
||||||
generateInstructions(right)
|
generateInstructions(right)
|
||||||
@@ -382,9 +373,9 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun visitAssignment(
|
private fun visitAssignment(
|
||||||
lhs: KtExpression?,
|
lhs: KtExpression?,
|
||||||
rhsDeferredValue: () -> PseudoValue?,
|
rhsDeferredValue: () -> PseudoValue?,
|
||||||
parentExpression: KtExpression
|
parentExpression: KtExpression
|
||||||
) {
|
) {
|
||||||
val left = KtPsiUtil.deparenthesize(lhs)
|
val left = KtPsiUtil.deparenthesize(lhs)
|
||||||
if (left == null) {
|
if (left == null) {
|
||||||
@@ -405,8 +396,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
if (accessTarget is AccessTarget.Call) {
|
if (accessTarget is AccessTarget.Call) {
|
||||||
receiverValues = getReceiverValues(accessTarget.resolvedCall)
|
receiverValues = getReceiverValues(accessTarget.resolvedCall)
|
||||||
}
|
}
|
||||||
}
|
} else if (left is KtProperty) {
|
||||||
else if (left is KtProperty) {
|
|
||||||
accessTarget = getDeclarationAccessTarget(left)
|
accessTarget = getDeclarationAccessTarget(left)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,9 +411,9 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateArrayAssignment(
|
private fun generateArrayAssignment(
|
||||||
lhs: KtArrayAccessExpression,
|
lhs: KtArrayAccessExpression,
|
||||||
rhsDeferredValue: () -> PseudoValue?,
|
rhsDeferredValue: () -> PseudoValue?,
|
||||||
parentExpression: KtExpression
|
parentExpression: KtExpression
|
||||||
) {
|
) {
|
||||||
val setResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_SET, lhs)
|
val setResolvedCall = trace.get(BindingContext.INDEXED_LVALUE_SET, lhs)
|
||||||
|
|
||||||
@@ -456,11 +446,11 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
* we first generate instructions for 1 and 2 whereas 3 is replaced by pseudo-value corresponding to "a.get(1) + 3"
|
* we first generate instructions for 1 and 2 whereas 3 is replaced by pseudo-value corresponding to "a.get(1) + 3"
|
||||||
*/
|
*/
|
||||||
private fun getArraySetterArguments(
|
private fun getArraySetterArguments(
|
||||||
rhsDeferredValue: () -> PseudoValue?,
|
rhsDeferredValue: () -> PseudoValue?,
|
||||||
setResolvedCall: ResolvedCall<FunctionDescriptor>
|
setResolvedCall: ResolvedCall<FunctionDescriptor>
|
||||||
): SmartFMap<PseudoValue, ValueParameterDescriptor> {
|
): SmartFMap<PseudoValue, ValueParameterDescriptor> {
|
||||||
val valueArguments = setResolvedCall.resultingDescriptor.valueParameters.flatMapTo(
|
val valueArguments = setResolvedCall.resultingDescriptor.valueParameters.flatMapTo(
|
||||||
ArrayList<ValueArgument>()
|
ArrayList<ValueArgument>()
|
||||||
) { descriptor -> setResolvedCall.valueArguments[descriptor]?.arguments ?: emptyList() }
|
) { descriptor -> setResolvedCall.valueArguments[descriptor]?.arguments ?: emptyList() }
|
||||||
|
|
||||||
val rhsArgument = valueArguments.lastOrNull()
|
val rhsArgument = valueArguments.lastOrNull()
|
||||||
@@ -470,8 +460,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
val parameterDescriptor = argumentMapping.valueParameter
|
val parameterDescriptor = argumentMapping.valueParameter
|
||||||
if (valueArgument !== rhsArgument) {
|
if (valueArgument !== rhsArgument) {
|
||||||
argumentValues = generateValueArgument(valueArgument, parameterDescriptor, argumentValues)
|
argumentValues = generateValueArgument(valueArgument, parameterDescriptor, argumentValues)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val rhsValue = rhsDeferredValue.invoke()
|
val rhsValue = rhsDeferredValue.invoke()
|
||||||
if (rhsValue != null) {
|
if (rhsValue != null) {
|
||||||
argumentValues = argumentValues.plus(rhsValue, parameterDescriptor)
|
argumentValues = argumentValues.plus(rhsValue, parameterDescriptor)
|
||||||
@@ -525,8 +514,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
|
|
||||||
val rhsValue: PseudoValue? = if (resolvedCall != null) {
|
val rhsValue: PseudoValue? = if (resolvedCall != null) {
|
||||||
generateCall(resolvedCall).outputValue
|
generateCall(resolvedCall).outputValue
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
generateInstructions(baseExpression)
|
generateInstructions(baseExpression)
|
||||||
createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, baseExpression)
|
createNonSyntheticValue(expression, MagicKind.UNRESOLVED_CALL, baseExpression)
|
||||||
}
|
}
|
||||||
@@ -540,7 +528,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isIncrementOrDecrement(operationType: IElementType): Boolean =
|
private fun isIncrementOrDecrement(operationType: IElementType): Boolean =
|
||||||
operationType === KtTokens.PLUSPLUS || operationType === KtTokens.MINUSMINUS
|
operationType === KtTokens.PLUSPLUS || operationType === KtTokens.MINUSMINUS
|
||||||
|
|
||||||
override fun visitIfExpression(expression: KtIfExpression) {
|
override fun visitIfExpression(expression: KtIfExpression) {
|
||||||
mark(expression)
|
mark(expression)
|
||||||
@@ -553,8 +541,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
if (thenBranch != null) {
|
if (thenBranch != null) {
|
||||||
branches.add(thenBranch)
|
branches.add(thenBranch)
|
||||||
generateInstructions(thenBranch)
|
generateInstructions(thenBranch)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
builder.loadUnit(expression)
|
builder.loadUnit(expression)
|
||||||
}
|
}
|
||||||
val resultLabel = builder.createUnboundLabel("'if' expression result")
|
val resultLabel = builder.createUnboundLabel("'if' expression result")
|
||||||
@@ -564,8 +551,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
if (elseBranch != null) {
|
if (elseBranch != null) {
|
||||||
branches.add(elseBranch)
|
branches.add(elseBranch)
|
||||||
generateInstructions(elseBranch)
|
generateInstructions(elseBranch)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
builder.loadUnit(expression)
|
builder.loadUnit(expression)
|
||||||
}
|
}
|
||||||
builder.bindLabel(resultLabel)
|
builder.bindLabel(resultLabel)
|
||||||
@@ -684,8 +670,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
builder.enterBlockScope(catchClause)
|
builder.enterBlockScope(catchClause)
|
||||||
if (!isFirst) {
|
if (!isFirst) {
|
||||||
builder.bindLabel(catchLabels.remove())
|
builder.bindLabel(catchLabels.remove())
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
isFirst = false
|
isFirst = false
|
||||||
}
|
}
|
||||||
val catchParameter = catchClause.catchParameter
|
val catchParameter = catchClause.catchParameter
|
||||||
@@ -713,8 +698,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
mark(expression)
|
mark(expression)
|
||||||
if (!CompileTimeConstantUtils.canBeReducedToBooleanConstant(condition, trace.bindingContext, true)) {
|
if (!CompileTimeConstantUtils.canBeReducedToBooleanConstant(condition, trace.bindingContext, true)) {
|
||||||
builder.jumpOnFalse(loopInfo.exitPoint, expression, builder.getBoundValue(condition))
|
builder.jumpOnFalse(loopInfo.exitPoint, expression, builder.getBoundValue(condition))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
assert(condition != null) { "Invalid while condition: " + expression.text }
|
assert(condition != null) { "Invalid while condition: " + expression.text }
|
||||||
createSyntheticValue(condition!!, MagicKind.VALUE_CONSUMER, condition)
|
createSyntheticValue(condition!!, MagicKind.VALUE_CONSUMER, condition)
|
||||||
}
|
}
|
||||||
@@ -741,8 +725,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
builder.exitBlockScope(expression)
|
builder.exitBlockScope(expression)
|
||||||
if (!CompileTimeConstantUtils.canBeReducedToBooleanConstant(condition, trace.bindingContext, true)) {
|
if (!CompileTimeConstantUtils.canBeReducedToBooleanConstant(condition, trace.bindingContext, true)) {
|
||||||
builder.jumpOnTrue(loopInfo.entryPoint, expression, builder.getBoundValue(expression.condition))
|
builder.jumpOnTrue(loopInfo.entryPoint, expression, builder.getBoundValue(expression.condition))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
assert(condition != null) { "Invalid do / while condition: " + expression.text }
|
assert(condition != null) { "Invalid do / while condition: " + expression.text }
|
||||||
createSyntheticValue(condition!!, MagicKind.VALUE_CONSUMER, condition)
|
createSyntheticValue(condition!!, MagicKind.VALUE_CONSUMER, condition)
|
||||||
builder.jump(loopInfo.entryPoint, expression)
|
builder.jump(loopInfo.entryPoint, expression)
|
||||||
@@ -781,8 +764,8 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateLoopConventionCall(
|
private fun generateLoopConventionCall(
|
||||||
loopRange: KtExpression?,
|
loopRange: KtExpression?,
|
||||||
callSlice: ReadOnlySlice<KtExpression, ResolvedCall<FunctionDescriptor>>
|
callSlice: ReadOnlySlice<KtExpression, ResolvedCall<FunctionDescriptor>>
|
||||||
) {
|
) {
|
||||||
if (loopRange == null) return
|
if (loopRange == null) return
|
||||||
val resolvedCall = trace.bindingContext[callSlice, loopRange] ?: return
|
val resolvedCall = trace.bindingContext[callSlice, loopRange] ?: return
|
||||||
@@ -795,8 +778,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
val destructuringDeclaration = loopParameter.destructuringDeclaration
|
val destructuringDeclaration = loopParameter.destructuringDeclaration
|
||||||
if (destructuringDeclaration != null) {
|
if (destructuringDeclaration != null) {
|
||||||
visitDestructuringDeclaration(destructuringDeclaration, false)
|
visitDestructuringDeclaration(destructuringDeclaration, false)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
builder.declareParameter(loopParameter)
|
builder.declareParameter(loopParameter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -807,10 +789,10 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
val loopRange = expression.loopRange
|
val loopRange = expression.loopRange
|
||||||
|
|
||||||
val value = builder.magic(
|
val value = builder.magic(
|
||||||
loopRange ?: expression,
|
loopRange ?: expression,
|
||||||
null,
|
null,
|
||||||
ContainerUtil.createMaybeSingletonList(builder.getBoundValue(loopRange)),
|
ContainerUtil.createMaybeSingletonList(builder.getBoundValue(loopRange)),
|
||||||
MagicKind.LOOP_RANGE_ITERATION
|
MagicKind.LOOP_RANGE_ITERATION
|
||||||
).outputValue
|
).outputValue
|
||||||
|
|
||||||
if (loopParameter != null) {
|
if (loopParameter != null) {
|
||||||
@@ -819,8 +801,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
for (entry in destructuringDeclaration.entries) {
|
for (entry in destructuringDeclaration.entries) {
|
||||||
generateInitializer(entry, value)
|
generateInitializer(entry, value)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
generateInitializer(loopParameter, value)
|
generateInitializer(loopParameter, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -857,8 +838,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
val parentBody = parentLoop.body
|
val parentBody = parentLoop.body
|
||||||
return if (parentBody != null && parentBody.textRange.contains(expression.textRange)) {
|
return if (parentBody != null && parentBody.textRange.contains(expression.textRange)) {
|
||||||
parentLoop
|
parentLoop
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
getNearestLoopExpression(parentLoop)
|
getNearestLoopExpression(parentLoop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -871,20 +851,19 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
val labeledElement = trace.get(BindingContext.LABEL_TARGET, targetLabel)
|
val labeledElement = trace.get(BindingContext.LABEL_TARGET, targetLabel)
|
||||||
loop = if (labeledElement is KtLoopExpression) {
|
loop = if (labeledElement is KtLoopExpression) {
|
||||||
labeledElement
|
labeledElement
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.text))
|
trace.report(NOT_A_LOOP_LABEL.on(expression, targetLabel.text))
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
loop = getCorrespondingLoopWithoutLabel(expression)
|
loop = getCorrespondingLoopWithoutLabel(expression)
|
||||||
if (loop == null) {
|
if (loop == null) {
|
||||||
trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression))
|
trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression))
|
||||||
}
|
} else {
|
||||||
else {
|
val whenExpression = PsiTreeUtil.getParentOfType(
|
||||||
val whenExpression = PsiTreeUtil.getParentOfType(expression, KtWhenExpression::class.java, true,
|
expression, KtWhenExpression::class.java, true,
|
||||||
KtLoopExpression::class.java)
|
KtLoopExpression::class.java
|
||||||
|
)
|
||||||
if (whenExpression != null) {
|
if (whenExpression != null) {
|
||||||
trace.report(BREAK_OR_CONTINUE_IN_WHEN.on(expression))
|
trace.report(BREAK_OR_CONTINUE_IN_WHEN.on(expression))
|
||||||
}
|
}
|
||||||
@@ -931,8 +910,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
trace.report(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY.on(jumpExpression))
|
trace.report(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY.on(jumpExpression))
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -953,12 +931,10 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
if (labeledElement != null) {
|
if (labeledElement != null) {
|
||||||
assert(labeledElement is KtElement)
|
assert(labeledElement is KtElement)
|
||||||
labeledElement as KtElement?
|
labeledElement as KtElement?
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
builder.returnSubroutine
|
builder.returnSubroutine
|
||||||
// TODO : a context check
|
// TODO : a context check
|
||||||
}
|
}
|
||||||
@@ -967,12 +943,10 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
val returnValue = if (returnedExpression != null) builder.getBoundValue(returnedExpression) else null
|
val returnValue = if (returnedExpression != null) builder.getBoundValue(returnedExpression) else null
|
||||||
if (returnValue == null) {
|
if (returnValue == null) {
|
||||||
builder.returnNoValue(expression, subroutine)
|
builder.returnNoValue(expression, subroutine)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
builder.returnValue(expression, returnValue, subroutine)
|
builder.returnValue(expression, returnValue, subroutine)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, returnedExpression)
|
createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, returnedExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1018,8 +992,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
}
|
}
|
||||||
if (statements.isEmpty()) {
|
if (statements.isEmpty()) {
|
||||||
builder.loadUnit(expression)
|
builder.loadUnit(expression)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
copyValue(statements.lastOrNull(), expression)
|
copyValue(statements.lastOrNull(), expression)
|
||||||
}
|
}
|
||||||
if (declareBlockScope) {
|
if (declareBlockScope) {
|
||||||
@@ -1035,8 +1008,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
private fun visitFunction(function: KtFunction, invocationKind: InvocationKind? = null) {
|
private fun visitFunction(function: KtFunction, invocationKind: InvocationKind? = null) {
|
||||||
if (invocationKind == null) {
|
if (invocationKind == null) {
|
||||||
processLocalDeclaration(function)
|
processLocalDeclaration(function)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
visitInlinedFunction(function, invocationKind)
|
visitInlinedFunction(function, invocationKind)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1093,16 +1065,14 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
if (selectorExpression is KtCallExpression || selectorExpression is KtSimpleNameExpression) {
|
if (selectorExpression is KtCallExpression || selectorExpression is KtSimpleNameExpression) {
|
||||||
if (!safe) {
|
if (!safe) {
|
||||||
generateInstructions(selectorExpression)
|
generateInstructions(selectorExpression)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val resultLabel = builder.createUnboundLabel("result of call")
|
val resultLabel = builder.createUnboundLabel("result of call")
|
||||||
builder.jumpOnFalse(resultLabel, expression, null)
|
builder.jumpOnFalse(resultLabel, expression, null)
|
||||||
generateInstructions(selectorExpression)
|
generateInstructions(selectorExpression)
|
||||||
builder.bindLabel(resultLabel)
|
builder.bindLabel(resultLabel)
|
||||||
}
|
}
|
||||||
copyValue(selectorExpression, expression)
|
copyValue(selectorExpression, expression)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
generateInstructions(receiverExpression)
|
generateInstructions(receiverExpression)
|
||||||
createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, receiverExpression)
|
createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, receiverExpression)
|
||||||
}
|
}
|
||||||
@@ -1182,12 +1152,12 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
val writtenValue: PseudoValue?
|
val writtenValue: PseudoValue?
|
||||||
writtenValue = if (resolvedCall != null) {
|
writtenValue = if (resolvedCall != null) {
|
||||||
builder.call(
|
builder.call(
|
||||||
entry,
|
entry,
|
||||||
resolvedCall,
|
resolvedCall,
|
||||||
getReceiverValues(resolvedCall),
|
getReceiverValues(resolvedCall),
|
||||||
emptyMap()).outputValue
|
emptyMap()
|
||||||
}
|
).outputValue
|
||||||
else {
|
} else {
|
||||||
initializer?.let { createSyntheticValue(entry, MagicKind.UNRESOLVED_CALL, it) }
|
initializer?.let { createSyntheticValue(entry, MagicKind.UNRESOLVED_CALL, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1211,8 +1181,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
if (getBoundOrUnreachableValue(left) != null) {
|
if (getBoundOrUnreachableValue(left) != null) {
|
||||||
createNonSyntheticValue(expression, MagicKind.CAST, left)
|
createNonSyntheticValue(expression, MagicKind.CAST, left)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
visitKtElement(expression)
|
visitKtElement(expression)
|
||||||
createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, left)
|
createNonSyntheticValue(expression, MagicKind.UNSUPPORTED_ELEMENT, left)
|
||||||
}
|
}
|
||||||
@@ -1376,8 +1345,10 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
val classDescriptor = trace[BindingContext.DECLARATION_TO_DESCRIPTOR, entryOrObject]
|
val classDescriptor = trace[BindingContext.DECLARATION_TO_DESCRIPTOR, entryOrObject]
|
||||||
if (classDescriptor is ClassDescriptor) {
|
if (classDescriptor is ClassDescriptor) {
|
||||||
builder.declareEntryOrObject(entryOrObject)
|
builder.declareEntryOrObject(entryOrObject)
|
||||||
builder.write(entryOrObject, entryOrObject, createSyntheticValue(entryOrObject, MagicKind.FAKE_INITIALIZER),
|
builder.write(
|
||||||
AccessTarget.Declaration(FakeCallableDescriptorForObject(classDescriptor)), emptyMap())
|
entryOrObject, entryOrObject, createSyntheticValue(entryOrObject, MagicKind.FAKE_INITIALIZER),
|
||||||
|
AccessTarget.Declaration(FakeCallableDescriptorForObject(classDescriptor)), emptyMap()
|
||||||
|
)
|
||||||
generateInstructions(entryOrObject)
|
generateInstructions(entryOrObject)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1431,7 +1402,8 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSecondaryConstructor(constructor: KtSecondaryConstructor) {
|
override fun visitSecondaryConstructor(constructor: KtSecondaryConstructor) {
|
||||||
val classOrObject = PsiTreeUtil.getParentOfType(constructor, KtClassOrObject::class.java) ?: error("Guaranteed by parsing contract")
|
val classOrObject =
|
||||||
|
PsiTreeUtil.getParentOfType(constructor, KtClassOrObject::class.java) ?: error("Guaranteed by parsing contract")
|
||||||
|
|
||||||
processParameters(constructor.valueParameters)
|
processParameters(constructor.valueParameters)
|
||||||
generateCallOrMarkUnresolved(constructor.getDelegationCall())
|
generateCallOrMarkUnresolved(constructor.getDelegationCall())
|
||||||
@@ -1493,8 +1465,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, receiverExpression) is DoubleColonLHS.Expression) {
|
trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, receiverExpression) is DoubleColonLHS.Expression) {
|
||||||
generateInstructions(receiverExpression)
|
generateInstructions(receiverExpression)
|
||||||
createNonSyntheticValue(expression, MagicKind.BOUND_CALLABLE_REFERENCE, receiverExpression)
|
createNonSyntheticValue(expression, MagicKind.BOUND_CALLABLE_REFERENCE, receiverExpression)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
createNonSyntheticValue(expression, MagicKind.UNBOUND_CALLABLE_REFERENCE)
|
createNonSyntheticValue(expression, MagicKind.UNBOUND_CALLABLE_REFERENCE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1541,8 +1512,7 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
val argumentExpression = argument.getArgumentExpression()
|
val argumentExpression = argument.getArgumentExpression()
|
||||||
if (argumentMapping is ArgumentMatch) {
|
if (argumentMapping is ArgumentMatch) {
|
||||||
parameterValues = generateValueArgument(argument, argumentMapping.valueParameter, parameterValues)
|
parameterValues = generateValueArgument(argument, argumentMapping.valueParameter, parameterValues)
|
||||||
}
|
} else if (argumentExpression != null) {
|
||||||
else if (argumentExpression != null) {
|
|
||||||
generateInstructions(argumentExpression)
|
generateInstructions(argumentExpression)
|
||||||
createSyntheticValue(argumentExpression, MagicKind.VALUE_CONSUMER, argumentExpression)
|
createSyntheticValue(argumentExpression, MagicKind.VALUE_CONSUMER, argumentExpression)
|
||||||
}
|
}
|
||||||
@@ -1551,7 +1521,8 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
if (resolvedCall.resultingDescriptor is VariableDescriptor) {
|
if (resolvedCall.resultingDescriptor is VariableDescriptor) {
|
||||||
// If a callee of the call is just a variable (without 'invoke'), 'read variable' is generated.
|
// If a callee of the call is just a variable (without 'invoke'), 'read variable' is generated.
|
||||||
// todo : process arguments for such a case (KT-5387)
|
// todo : process arguments for such a case (KT-5387)
|
||||||
val callExpression = callElement as? KtExpression ?: error("Variable-based call without callee expression: " + callElement.text)
|
val callExpression =
|
||||||
|
callElement as? KtExpression ?: error("Variable-based call without callee expression: " + callElement.text)
|
||||||
assert(parameterValues.isEmpty()) { "Variable-based call with non-empty argument list: " + callElement.text }
|
assert(parameterValues.isEmpty()) { "Variable-based call with non-empty argument list: " + callElement.text }
|
||||||
return builder.readVariable(callExpression, resolvedCall, receivers)
|
return builder.readVariable(callExpression, resolvedCall, receivers)
|
||||||
}
|
}
|
||||||
@@ -1589,9 +1560,9 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getReceiverValues(
|
private fun getReceiverValues(
|
||||||
callElement: KtElement,
|
callElement: KtElement,
|
||||||
receiver: ReceiverValue?,
|
receiver: ReceiverValue?,
|
||||||
receiverValuesArg: SmartFMap<PseudoValue, ReceiverValue>
|
receiverValuesArg: SmartFMap<PseudoValue, ReceiverValue>
|
||||||
): SmartFMap<PseudoValue, ReceiverValue> {
|
): SmartFMap<PseudoValue, ReceiverValue> {
|
||||||
var receiverValues = receiverValuesArg
|
var receiverValues = receiverValuesArg
|
||||||
if (receiver == null || receiverValues.containsValue(receiver)) return receiverValues
|
if (receiver == null || receiverValues.containsValue(receiver)) return receiverValues
|
||||||
@@ -1633,9 +1604,9 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateValueArgument(
|
private fun generateValueArgument(
|
||||||
valueArgument: ValueArgument,
|
valueArgument: ValueArgument,
|
||||||
parameterDescriptor: ValueParameterDescriptor,
|
parameterDescriptor: ValueParameterDescriptor,
|
||||||
parameterValuesArg: SmartFMap<PseudoValue, ValueParameterDescriptor>
|
parameterValuesArg: SmartFMap<PseudoValue, ValueParameterDescriptor>
|
||||||
): SmartFMap<PseudoValue, ValueParameterDescriptor> {
|
): SmartFMap<PseudoValue, ValueParameterDescriptor> {
|
||||||
var parameterValues = parameterValuesArg
|
var parameterValues = parameterValuesArg
|
||||||
val expression = valueArgument.getArgumentExpression()
|
val expression = valueArgument.getArgumentExpression()
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ package org.jetbrains.kotlin.cfg
|
|||||||
import org.jetbrains.kotlin.psi.KtLoopExpression
|
import org.jetbrains.kotlin.psi.KtLoopExpression
|
||||||
|
|
||||||
class LoopInfo(
|
class LoopInfo(
|
||||||
override val element: KtLoopExpression,
|
override val element: KtLoopExpression,
|
||||||
entryPoint: Label,
|
entryPoint: Label,
|
||||||
exitPoint: Label,
|
exitPoint: Label,
|
||||||
val bodyEntryPoint: Label,
|
val bodyEntryPoint: Label,
|
||||||
val bodyExitPoint: Label,
|
val bodyExitPoint: Label,
|
||||||
val conditionEntryPoint: Label
|
val conditionEntryPoint: Label
|
||||||
) : BreakableBlockInfo(element, entryPoint, exitPoint) {
|
) : BreakableBlockInfo(element, entryPoint, exitPoint) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder.FORWARD
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
fun Pseudocode.traverse(
|
fun Pseudocode.traverse(
|
||||||
traversalOrder: TraversalOrder,
|
traversalOrder: TraversalOrder,
|
||||||
analyzeInstruction: (Instruction) -> Unit
|
analyzeInstruction: (Instruction) -> Unit
|
||||||
) {
|
) {
|
||||||
val instructions = getInstructions(traversalOrder)
|
val instructions = getInstructions(traversalOrder)
|
||||||
for (instruction in instructions) {
|
for (instruction in instructions) {
|
||||||
@@ -40,9 +40,9 @@ fun Pseudocode.traverse(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <D> Pseudocode.traverse(
|
fun <D> Pseudocode.traverse(
|
||||||
traversalOrder: TraversalOrder,
|
traversalOrder: TraversalOrder,
|
||||||
edgesMap: Map<Instruction, Edges<D>>,
|
edgesMap: Map<Instruction, Edges<D>>,
|
||||||
analyzeInstruction: (Instruction, D, D) -> Unit
|
analyzeInstruction: (Instruction, D, D) -> Unit
|
||||||
) {
|
) {
|
||||||
val instructions = getInstructions(traversalOrder)
|
val instructions = getInstructions(traversalOrder)
|
||||||
for (instruction in instructions) {
|
for (instruction in instructions) {
|
||||||
@@ -57,10 +57,10 @@ fun <D> Pseudocode.traverse(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <I : ControlFlowInfo<*, *>> Pseudocode.collectData(
|
fun <I : ControlFlowInfo<*, *>> Pseudocode.collectData(
|
||||||
traversalOrder: TraversalOrder,
|
traversalOrder: TraversalOrder,
|
||||||
mergeEdges: (Instruction, Collection<I>) -> Edges<I>,
|
mergeEdges: (Instruction, Collection<I>) -> Edges<I>,
|
||||||
updateEdge: (Instruction, Instruction, I) -> I,
|
updateEdge: (Instruction, Instruction, I) -> I,
|
||||||
initialInfo: I
|
initialInfo: I
|
||||||
): Map<Instruction, Edges<I>> {
|
): Map<Instruction, Edges<I>> {
|
||||||
val edgesMap = LinkedHashMap<Instruction, Edges<I>>()
|
val edgesMap = LinkedHashMap<Instruction, Edges<I>>()
|
||||||
edgesMap.put(getStartInstruction(traversalOrder), Edges(initialInfo, initialInfo))
|
edgesMap.put(getStartInstruction(traversalOrder), Edges(initialInfo, initialInfo))
|
||||||
@@ -68,21 +68,22 @@ fun <I : ControlFlowInfo<*, *>> Pseudocode.collectData(
|
|||||||
val changed = mutableMapOf<Instruction, Boolean>()
|
val changed = mutableMapOf<Instruction, Boolean>()
|
||||||
do {
|
do {
|
||||||
collectDataFromSubgraph(
|
collectDataFromSubgraph(
|
||||||
traversalOrder, edgesMap,
|
traversalOrder, edgesMap,
|
||||||
mergeEdges, updateEdge, Collections.emptyList<Instruction>(), changed, false)
|
mergeEdges, updateEdge, Collections.emptyList<Instruction>(), changed, false
|
||||||
|
)
|
||||||
} while (changed.any { it.value })
|
} while (changed.any { it.value })
|
||||||
|
|
||||||
return edgesMap
|
return edgesMap
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <I : ControlFlowInfo<*, *>> Pseudocode.collectDataFromSubgraph(
|
private fun <I : ControlFlowInfo<*, *>> Pseudocode.collectDataFromSubgraph(
|
||||||
traversalOrder: TraversalOrder,
|
traversalOrder: TraversalOrder,
|
||||||
edgesMap: MutableMap<Instruction, Edges<I>>,
|
edgesMap: MutableMap<Instruction, Edges<I>>,
|
||||||
mergeEdges: (Instruction, Collection<I>) -> Edges<I>,
|
mergeEdges: (Instruction, Collection<I>) -> Edges<I>,
|
||||||
updateEdge: (Instruction, Instruction, I) -> I,
|
updateEdge: (Instruction, Instruction, I) -> I,
|
||||||
previousSubGraphInstructions: Collection<Instruction>,
|
previousSubGraphInstructions: Collection<Instruction>,
|
||||||
changed: MutableMap<Instruction, Boolean>,
|
changed: MutableMap<Instruction, Boolean>,
|
||||||
isLocal: Boolean
|
isLocal: Boolean
|
||||||
) {
|
) {
|
||||||
val instructions = getInstructions(traversalOrder)
|
val instructions = getInstructions(traversalOrder)
|
||||||
val startInstruction = getStartInstruction(traversalOrder)
|
val startInstruction = getStartInstruction(traversalOrder)
|
||||||
@@ -92,12 +93,13 @@ private fun <I : ControlFlowInfo<*, *>> Pseudocode.collectDataFromSubgraph(
|
|||||||
if (!isLocal && isStart)
|
if (!isLocal && isStart)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
val previousInstructions = getPreviousIncludingSubGraphInstructions(instruction, traversalOrder, startInstruction, previousSubGraphInstructions)
|
val previousInstructions =
|
||||||
|
getPreviousIncludingSubGraphInstructions(instruction, traversalOrder, startInstruction, previousSubGraphInstructions)
|
||||||
|
|
||||||
if (instruction is LocalFunctionDeclarationInstruction) {
|
if (instruction is LocalFunctionDeclarationInstruction) {
|
||||||
val subroutinePseudocode = instruction.body
|
val subroutinePseudocode = instruction.body
|
||||||
subroutinePseudocode.collectDataFromSubgraph(
|
subroutinePseudocode.collectDataFromSubgraph(
|
||||||
traversalOrder, edgesMap, mergeEdges, updateEdge, previousInstructions, changed, true
|
traversalOrder, edgesMap, mergeEdges, updateEdge, previousInstructions, changed, true
|
||||||
)
|
)
|
||||||
// Special case for inlined functions: take flow from EXIT instructions (it contains flow which exits declaration normally)
|
// Special case for inlined functions: take flow from EXIT instructions (it contains flow which exits declaration normally)
|
||||||
val lastInstruction = if (instruction is InlinedLocalFunctionDeclarationInstruction && traversalOrder == FORWARD)
|
val lastInstruction = if (instruction is InlinedLocalFunctionDeclarationInstruction && traversalOrder == FORWARD)
|
||||||
@@ -125,8 +127,11 @@ private fun <I : ControlFlowInfo<*, *>> Pseudocode.collectDataFromSubgraph(
|
|||||||
for (previousInstruction in previousInstructions) {
|
for (previousInstruction in previousInstructions) {
|
||||||
val previousData = edgesMap[previousInstruction]
|
val previousData = edgesMap[previousInstruction]
|
||||||
if (previousData != null) {
|
if (previousData != null) {
|
||||||
incomingEdgesData.add(updateEdge(
|
incomingEdgesData.add(
|
||||||
previousInstruction, instruction, previousData.outgoing))
|
updateEdge(
|
||||||
|
previousInstruction, instruction, previousData.outgoing
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val mergedData = mergeEdges(instruction, incomingEdgesData)
|
val mergedData = mergeEdges(instruction, incomingEdgesData)
|
||||||
@@ -135,10 +140,10 @@ private fun <I : ControlFlowInfo<*, *>> Pseudocode.collectDataFromSubgraph(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getPreviousIncludingSubGraphInstructions(
|
private fun getPreviousIncludingSubGraphInstructions(
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
traversalOrder: TraversalOrder,
|
traversalOrder: TraversalOrder,
|
||||||
startInstruction: Instruction,
|
startInstruction: Instruction,
|
||||||
previousSubGraphInstructions: Collection<Instruction>
|
previousSubGraphInstructions: Collection<Instruction>
|
||||||
): Collection<Instruction> {
|
): Collection<Instruction> {
|
||||||
val previous = instruction.getPreviousInstructions(traversalOrder)
|
val previous = instruction.getPreviousInstructions(traversalOrder)
|
||||||
if (instruction != startInstruction || previousSubGraphInstructions.isEmpty()) {
|
if (instruction != startInstruction || previousSubGraphInstructions.isEmpty()) {
|
||||||
@@ -150,17 +155,16 @@ private fun getPreviousIncludingSubGraphInstructions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun <I : ControlFlowInfo<*, *>> updateEdgeDataForInstruction(
|
private fun <I : ControlFlowInfo<*, *>> updateEdgeDataForInstruction(
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
previousValue: Edges<I>?,
|
previousValue: Edges<I>?,
|
||||||
newValue: Edges<I>?,
|
newValue: Edges<I>?,
|
||||||
edgesMap: MutableMap<Instruction, Edges<I>>,
|
edgesMap: MutableMap<Instruction, Edges<I>>,
|
||||||
changed: MutableMap<Instruction, Boolean>
|
changed: MutableMap<Instruction, Boolean>
|
||||||
) {
|
) {
|
||||||
if (previousValue != newValue && newValue != null) {
|
if (previousValue != newValue && newValue != null) {
|
||||||
changed[instruction] = true
|
changed[instruction] = true
|
||||||
edgesMap.put(instruction, newValue)
|
edgesMap.put(instruction, newValue)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
changed[instruction] = false
|
changed[instruction] = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,11 +179,11 @@ enum class TraverseInstructionResult {
|
|||||||
|
|
||||||
// returns false when interrupted by handler
|
// returns false when interrupted by handler
|
||||||
fun traverseFollowingInstructions(
|
fun traverseFollowingInstructions(
|
||||||
rootInstruction: Instruction,
|
rootInstruction: Instruction,
|
||||||
visited: MutableSet<Instruction> = HashSet(),
|
visited: MutableSet<Instruction> = HashSet(),
|
||||||
order: TraversalOrder = FORWARD,
|
order: TraversalOrder = FORWARD,
|
||||||
// true to continue traversal
|
// true to continue traversal
|
||||||
handler: ((Instruction) -> TraverseInstructionResult)?
|
handler: ((Instruction) -> TraverseInstructionResult)?
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val stack = ArrayDeque<Instruction>()
|
val stack = ArrayDeque<Instruction>()
|
||||||
stack.push(rootInstruction)
|
stack.push(rootInstruction)
|
||||||
@@ -189,7 +193,8 @@ fun traverseFollowingInstructions(
|
|||||||
if (!visited.add(instruction)) continue
|
if (!visited.add(instruction)) continue
|
||||||
when (handler?.let { it(instruction) } ?: TraverseInstructionResult.CONTINUE) {
|
when (handler?.let { it(instruction) } ?: TraverseInstructionResult.CONTINUE) {
|
||||||
TraverseInstructionResult.CONTINUE -> instruction.getNextInstructions(order).forEach { stack.push(it) }
|
TraverseInstructionResult.CONTINUE -> instruction.getNextInstructions(order).forEach { stack.push(it) }
|
||||||
TraverseInstructionResult.SKIP -> {}
|
TraverseInstructionResult.SKIP -> {
|
||||||
|
}
|
||||||
TraverseInstructionResult.HALT -> return false
|
TraverseInstructionResult.HALT -> return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,19 +207,19 @@ enum class TraversalOrder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Pseudocode.getStartInstruction(traversalOrder: TraversalOrder): Instruction =
|
fun Pseudocode.getStartInstruction(traversalOrder: TraversalOrder): Instruction =
|
||||||
if (traversalOrder == FORWARD) enterInstruction else sinkInstruction
|
if (traversalOrder == FORWARD) enterInstruction else sinkInstruction
|
||||||
|
|
||||||
fun Pseudocode.getLastInstruction(traversalOrder: TraversalOrder): Instruction =
|
fun Pseudocode.getLastInstruction(traversalOrder: TraversalOrder): Instruction =
|
||||||
if (traversalOrder == FORWARD) sinkInstruction else enterInstruction
|
if (traversalOrder == FORWARD) sinkInstruction else enterInstruction
|
||||||
|
|
||||||
fun Pseudocode.getInstructions(traversalOrder: TraversalOrder): List<Instruction> =
|
fun Pseudocode.getInstructions(traversalOrder: TraversalOrder): List<Instruction> =
|
||||||
if (traversalOrder == FORWARD) instructions else reversedInstructions
|
if (traversalOrder == FORWARD) instructions else reversedInstructions
|
||||||
|
|
||||||
fun Instruction.getNextInstructions(traversalOrder: TraversalOrder): Collection<Instruction> =
|
fun Instruction.getNextInstructions(traversalOrder: TraversalOrder): Collection<Instruction> =
|
||||||
if (traversalOrder == FORWARD) nextInstructions else previousInstructions
|
if (traversalOrder == FORWARD) nextInstructions else previousInstructions
|
||||||
|
|
||||||
fun Instruction.getPreviousInstructions(traversalOrder: TraversalOrder): Collection<Instruction> =
|
fun Instruction.getPreviousInstructions(traversalOrder: TraversalOrder): Collection<Instruction> =
|
||||||
if (traversalOrder == FORWARD) previousInstructions else nextInstructions
|
if (traversalOrder == FORWARD) previousInstructions else nextInstructions
|
||||||
|
|
||||||
fun Instruction.isStartInstruction(traversalOrder: TraversalOrder): Boolean =
|
fun Instruction.isStartInstruction(traversalOrder: TraversalOrder): Boolean =
|
||||||
if (traversalOrder == FORWARD) this is SubroutineEnterInstruction else this is SubroutineSinkInstruction
|
if (traversalOrder == FORWARD) this is SubroutineEnterInstruction else this is SubroutineSinkInstruction
|
||||||
|
|||||||
@@ -20,14 +20,14 @@ import org.jetbrains.kotlin.psi.KtElement
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValue
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValue
|
||||||
|
|
||||||
class PseudoValueImpl(
|
class PseudoValueImpl(
|
||||||
override val debugName: String,
|
override val debugName: String,
|
||||||
override val element: KtElement?,
|
override val element: KtElement?,
|
||||||
override val createdAt: InstructionWithValue?
|
override val createdAt: InstructionWithValue?
|
||||||
) : PseudoValue {
|
) : PseudoValue {
|
||||||
override fun toString(): String = debugName
|
override fun toString(): String = debugName
|
||||||
}
|
}
|
||||||
|
|
||||||
open class PseudoValueFactoryImpl: PseudoValueFactory {
|
open class PseudoValueFactoryImpl : PseudoValueFactory {
|
||||||
private var lastIndex: Int = 0
|
private var lastIndex: Int = 0
|
||||||
|
|
||||||
override fun newValue(element: KtElement?, instruction: InstructionWithValue?): PseudoValue {
|
override fun newValue(element: KtElement?, instruction: InstructionWithValue?): PseudoValue {
|
||||||
|
|||||||
@@ -109,7 +109,12 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
|
|||||||
override val reversedInstructions: List<Instruction>
|
override val reversedInstructions: List<Instruction>
|
||||||
get() {
|
get() {
|
||||||
val traversedInstructions = linkedSetOf<Instruction>()
|
val traversedInstructions = linkedSetOf<Instruction>()
|
||||||
traverseFollowingInstructions(if (this.isInlined) instructions.last() else sinkInstruction, traversedInstructions, BACKWARD, null)
|
traverseFollowingInstructions(
|
||||||
|
if (this.isInlined) instructions.last() else sinkInstruction,
|
||||||
|
traversedInstructions,
|
||||||
|
BACKWARD,
|
||||||
|
null
|
||||||
|
)
|
||||||
if (traversedInstructions.size < instructions.size) {
|
if (traversedInstructions.size < instructions.size) {
|
||||||
val simplyReversedInstructions = instructions.reversed()
|
val simplyReversedInstructions = instructions.reversed()
|
||||||
for (instruction in simplyReversedInstructions) {
|
for (instruction in simplyReversedInstructions) {
|
||||||
@@ -194,8 +199,8 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
|
|||||||
fun bindLabel(label: PseudocodeLabel) {
|
fun bindLabel(label: PseudocodeLabel) {
|
||||||
assert(this == label.pseudocode) {
|
assert(this == label.pseudocode) {
|
||||||
"Attempt to bind label $label to instruction from different pseudocode: " +
|
"Attempt to bind label $label to instruction from different pseudocode: " +
|
||||||
"\nowner pseudocode = ${label.pseudocode.mutableInstructionList}, " +
|
"\nowner pseudocode = ${label.pseudocode.mutableInstructionList}, " +
|
||||||
"\nbound pseudocode = ${this.mutableInstructionList}"
|
"\nbound pseudocode = ${this.mutableInstructionList}"
|
||||||
}
|
}
|
||||||
label.targetInstructionIndex = mutableInstructionList.size
|
label.targetInstructionIndex = mutableInstructionList.size
|
||||||
}
|
}
|
||||||
@@ -214,7 +219,7 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
|
|||||||
private fun addValueUsage(value: PseudoValue, usage: Instruction) {
|
private fun addValueUsage(value: PseudoValue, usage: Instruction) {
|
||||||
if (usage is MergeInstruction) return
|
if (usage is MergeInstruction) return
|
||||||
valueUsages.getOrPut(
|
valueUsages.getOrPut(
|
||||||
value
|
value
|
||||||
) { arrayListOf() }.add(usage)
|
) { arrayListOf() }.add(usage)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,8 +271,7 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
|
|||||||
if (instruction.onTrue) {
|
if (instruction.onTrue) {
|
||||||
instruction.nextOnFalse = nextInstruction
|
instruction.nextOnFalse = nextInstruction
|
||||||
instruction.nextOnTrue = jumpTarget
|
instruction.nextOnTrue = jumpTarget
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
instruction.nextOnFalse = jumpTarget
|
instruction.nextOnFalse = jumpTarget
|
||||||
instruction.nextOnTrue = nextInstruction
|
instruction.nextOnTrue = nextInstruction
|
||||||
}
|
}
|
||||||
@@ -286,7 +290,8 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
|
|||||||
body.parent = this@PseudocodeImpl
|
body.parent = this@PseudocodeImpl
|
||||||
body.postProcess()
|
body.postProcess()
|
||||||
// Don't add edge to next instruction if flow can't reach exit of inlined declaration
|
// Don't add edge to next instruction if flow can't reach exit of inlined declaration
|
||||||
instruction.next = if (body.instructions.contains(body.exitInstruction)) getNextPosition(currentPosition) else sinkInstruction
|
instruction.next =
|
||||||
|
if (body.instructions.contains(body.exitInstruction)) getNextPosition(currentPosition) else sinkInstruction
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSubroutineExit(instruction: SubroutineExitInstruction) {
|
override fun visitSubroutineExit(instruction: SubroutineExitInstruction) {
|
||||||
@@ -305,7 +310,8 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
|
|||||||
|
|
||||||
private fun collectReachableInstructions() {
|
private fun collectReachableInstructions() {
|
||||||
val reachableFromThisPseudocode = hashSetOf<Instruction>()
|
val reachableFromThisPseudocode = hashSetOf<Instruction>()
|
||||||
traverseFollowingInstructions(enterInstruction, reachableFromThisPseudocode, FORWARD
|
traverseFollowingInstructions(
|
||||||
|
enterInstruction, reachableFromThisPseudocode, FORWARD
|
||||||
) { instruction ->
|
) { instruction ->
|
||||||
if (instruction is MagicInstruction && instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) {
|
if (instruction is MagicInstruction && instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) {
|
||||||
return@traverseFollowingInstructions TraverseInstructionResult.SKIP
|
return@traverseFollowingInstructions TraverseInstructionResult.SKIP
|
||||||
@@ -358,12 +364,13 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun repeatPart(startLabel: Label, finishLabel: Label, labelCount: Int): Int =
|
fun repeatPart(startLabel: Label, finishLabel: Label, labelCount: Int): Int =
|
||||||
repeatInternal(startLabel.pseudocode as PseudocodeImpl, startLabel, finishLabel, labelCount)
|
repeatInternal(startLabel.pseudocode as PseudocodeImpl, startLabel, finishLabel, labelCount)
|
||||||
|
|
||||||
private fun repeatInternal(
|
private fun repeatInternal(
|
||||||
originalPseudocode: PseudocodeImpl,
|
originalPseudocode: PseudocodeImpl,
|
||||||
startLabel: Label?, finishLabel: Label?,
|
startLabel: Label?, finishLabel: Label?,
|
||||||
labelCountArg: Int): Int {
|
labelCountArg: Int
|
||||||
|
): Int {
|
||||||
var labelCount = labelCountArg
|
var labelCount = labelCountArg
|
||||||
val startIndex = startLabel?.targetInstructionIndex ?: 0
|
val startIndex = startLabel?.targetInstructionIndex ?: 0
|
||||||
val finishIndex = finishLabel?.targetInstructionIndex ?: originalPseudocode.mutableInstructionList.size
|
val finishIndex = finishLabel?.targetInstructionIndex ?: originalPseudocode.mutableInstructionList.size
|
||||||
@@ -401,17 +408,20 @@ class PseudocodeImpl(override val correspondingElement: KtElement, override val
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (finishIndex < originalPseudocode.mutableInstructionList.size) {
|
if (finishIndex < originalPseudocode.mutableInstructionList.size) {
|
||||||
repeatLabelsBindingForInstruction(originalPseudocode.mutableInstructionList[finishIndex],
|
repeatLabelsBindingForInstruction(
|
||||||
originalToCopy,
|
originalPseudocode.mutableInstructionList[finishIndex],
|
||||||
originalLabelsForInstruction)
|
originalToCopy,
|
||||||
|
originalLabelsForInstruction
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return labelCount
|
return labelCount
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun repeatLabelsBindingForInstruction(
|
private fun repeatLabelsBindingForInstruction(
|
||||||
originalInstruction: Instruction,
|
originalInstruction: Instruction,
|
||||||
originalToCopy: Map<Label, PseudocodeLabel>,
|
originalToCopy: Map<Label, PseudocodeLabel>,
|
||||||
originalLabelsForInstruction: Multimap<Instruction, Label>) {
|
originalLabelsForInstruction: Multimap<Instruction, Label>
|
||||||
|
) {
|
||||||
for (originalLabel in originalLabelsForInstruction.get(originalInstruction)) {
|
for (originalLabel in originalLabelsForInstruction.get(originalInstruction)) {
|
||||||
bindLabel(originalToCopy[originalLabel]!!)
|
bindLabel(originalToCopy[originalLabel]!!)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
|||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
|
||||||
class PseudocodeLabel internal constructor(
|
class PseudocodeLabel internal constructor(
|
||||||
override val pseudocode: PseudocodeImpl, override val name: String, private val comment: String?
|
override val pseudocode: PseudocodeImpl, override val name: String, private val comment: String?
|
||||||
) : Label {
|
) : Label {
|
||||||
|
|
||||||
private val instructionList: List<Instruction> get() = pseudocode.mutableInstructionList
|
private val instructionList: List<Instruction> get() = pseudocode.mutableInstructionList
|
||||||
@@ -36,16 +36,20 @@ class PseudocodeLabel internal constructor(
|
|||||||
val index = targetInstructionIndex
|
val index = targetInstructionIndex
|
||||||
when {
|
when {
|
||||||
index < 0 ->
|
index < 0 ->
|
||||||
error("resolveToInstruction: unbound label $name " +
|
error(
|
||||||
"in subroutine ${correspondingElement.text} with instructions $instructionList")
|
"resolveToInstruction: unbound label $name " +
|
||||||
|
"in subroutine ${correspondingElement.text} with instructions $instructionList"
|
||||||
|
)
|
||||||
index >= instructionList.size ->
|
index >= instructionList.size ->
|
||||||
error("resolveToInstruction: incorrect index $index for label $name " +
|
error(
|
||||||
"in subroutine ${correspondingElement.text} with instructions $instructionList")
|
"resolveToInstruction: incorrect index $index for label $name " +
|
||||||
|
"in subroutine ${correspondingElement.text} with instructions $instructionList"
|
||||||
|
)
|
||||||
else ->
|
else ->
|
||||||
return instructionList[index]
|
return instructionList[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copy(newPseudocode: PseudocodeImpl, newLabelIndex: Int): PseudocodeLabel =
|
fun copy(newPseudocode: PseudocodeImpl, newLabelIndex: Int): PseudocodeLabel =
|
||||||
PseudocodeLabel(newPseudocode, "L" + newLabelIndex, "copy of $name, $comment")
|
PseudocodeLabel(newPseudocode, "L" + newLabelIndex, "copy of $name, $comment")
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ import java.util.LinkedHashSet
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
|
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
|
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
|
||||||
|
|
||||||
abstract class InstructionImpl(override val blockScope: BlockScope): Instruction {
|
abstract class InstructionImpl(override val blockScope: BlockScope) : Instruction {
|
||||||
private var _owner: Pseudocode? = null
|
private var _owner: Pseudocode? = null
|
||||||
|
|
||||||
override var owner: Pseudocode
|
override var owner: Pseudocode
|
||||||
|
|||||||
+2
-2
@@ -28,10 +28,10 @@ abstract class InstructionVisitorWithResult<out R> {
|
|||||||
open fun visitReadValue(instruction: ReadValueInstruction): R = visitAccessInstruction(instruction)
|
open fun visitReadValue(instruction: ReadValueInstruction): R = visitAccessInstruction(instruction)
|
||||||
|
|
||||||
open fun visitLocalFunctionDeclarationInstruction(instruction: LocalFunctionDeclarationInstruction): R =
|
open fun visitLocalFunctionDeclarationInstruction(instruction: LocalFunctionDeclarationInstruction): R =
|
||||||
visitInstructionWithNext(instruction)
|
visitInstructionWithNext(instruction)
|
||||||
|
|
||||||
open fun visitInlinedFunctionDeclarationInstruction(instruction: InlinedLocalFunctionDeclarationInstruction): R =
|
open fun visitInlinedFunctionDeclarationInstruction(instruction: InlinedLocalFunctionDeclarationInstruction): R =
|
||||||
visitLocalFunctionDeclarationInstruction(instruction)
|
visitLocalFunctionDeclarationInstruction(instruction)
|
||||||
|
|
||||||
open fun visitVariableDeclarationInstruction(instruction: VariableDeclarationInstruction): R = visitInstructionWithNext(instruction)
|
open fun visitVariableDeclarationInstruction(instruction: VariableDeclarationInstruction): R = visitInstructionWithNext(instruction)
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -19,8 +19,8 @@ package org.jetbrains.kotlin.cfg.pseudocode.instructions
|
|||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
|
||||||
abstract class InstructionWithNext(
|
abstract class InstructionWithNext(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
blockScope: BlockScope
|
blockScope: BlockScope
|
||||||
) : KtElementInstructionImpl(element, blockScope) {
|
) : KtElementInstructionImpl(element, blockScope) {
|
||||||
var next: Instruction? = null
|
var next: Instruction? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
|
|||||||
+3
-3
@@ -20,9 +20,9 @@ import com.intellij.psi.PsiElement
|
|||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
|
||||||
abstract class KtElementInstructionImpl(
|
abstract class KtElementInstructionImpl(
|
||||||
override val element: KtElement,
|
override val element: KtElement,
|
||||||
blockScope: BlockScope
|
blockScope: BlockScope
|
||||||
) : InstructionImpl(blockScope), KtElementInstruction {
|
) : InstructionImpl(blockScope), KtElementInstruction {
|
||||||
protected fun render(element: PsiElement): String =
|
protected fun render(element: PsiElement): String =
|
||||||
element.text?.replace("\\s+".toRegex(), " ") ?: ""
|
element.text?.replace("\\s+".toRegex(), " ") ?: ""
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -20,6 +20,6 @@ import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
|
|
||||||
interface InstructionWithReceivers: Instruction {
|
interface InstructionWithReceivers : Instruction {
|
||||||
val receiverValues: Map<PseudoValue, ReceiverValue>
|
val receiverValues: Map<PseudoValue, ReceiverValue>
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -24,8 +24,8 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
|
||||||
|
|
||||||
class LoadUnitValueInstruction(
|
class LoadUnitValueInstruction(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
blockScope: BlockScope
|
blockScope: BlockScope
|
||||||
) : InstructionWithNext(expression, blockScope) {
|
) : InstructionWithNext(expression, blockScope) {
|
||||||
override fun accept(visitor: InstructionVisitor) {
|
override fun accept(visitor: InstructionVisitor) {
|
||||||
visitor.visitLoadUnitValue(this)
|
visitor.visitLoadUnitValue(this)
|
||||||
@@ -36,8 +36,8 @@ class LoadUnitValueInstruction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String =
|
override fun toString(): String =
|
||||||
"read (Unit)"
|
"read (Unit)"
|
||||||
|
|
||||||
override fun createCopy(): InstructionImpl =
|
override fun createCopy(): InstructionImpl =
|
||||||
LoadUnitValueInstruction(element as KtExpression, blockScope)
|
LoadUnitValueInstruction(element as KtExpression, blockScope)
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-24
@@ -27,17 +27,19 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
|||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
|
|
||||||
sealed class AccessTarget {
|
sealed class AccessTarget {
|
||||||
class Declaration(val descriptor: VariableDescriptor): AccessTarget() {
|
class Declaration(val descriptor: VariableDescriptor) : AccessTarget() {
|
||||||
override fun equals(other: Any?) = other is Declaration && descriptor == other.descriptor
|
override fun equals(other: Any?) = other is Declaration && descriptor == other.descriptor
|
||||||
|
|
||||||
override fun hashCode() = descriptor.hashCode()
|
override fun hashCode() = descriptor.hashCode()
|
||||||
}
|
}
|
||||||
class Call(val resolvedCall: ResolvedCall<*>): AccessTarget() {
|
|
||||||
|
class Call(val resolvedCall: ResolvedCall<*>) : AccessTarget() {
|
||||||
override fun equals(other: Any?) = other is Call && resolvedCall == other.resolvedCall
|
override fun equals(other: Any?) = other is Call && resolvedCall == other.resolvedCall
|
||||||
|
|
||||||
override fun hashCode() = resolvedCall.hashCode()
|
override fun hashCode() = resolvedCall.hashCode()
|
||||||
}
|
}
|
||||||
object BlackBox: AccessTarget()
|
|
||||||
|
object BlackBox : AccessTarget()
|
||||||
}
|
}
|
||||||
|
|
||||||
val AccessTarget.accessedDescriptor: CallableDescriptor?
|
val AccessTarget.accessedDescriptor: CallableDescriptor?
|
||||||
@@ -48,26 +50,26 @@ val AccessTarget.accessedDescriptor: CallableDescriptor?
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class AccessValueInstruction protected constructor(
|
abstract class AccessValueInstruction protected constructor(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
val target: AccessTarget,
|
val target: AccessTarget,
|
||||||
override val receiverValues: Map<PseudoValue, ReceiverValue>
|
override val receiverValues: Map<PseudoValue, ReceiverValue>
|
||||||
) : InstructionWithNext(element, blockScope), InstructionWithReceivers
|
) : InstructionWithNext(element, blockScope), InstructionWithReceivers
|
||||||
|
|
||||||
class ReadValueInstruction private constructor(
|
class ReadValueInstruction private constructor(
|
||||||
|
element: KtElement,
|
||||||
|
blockScope: BlockScope,
|
||||||
|
target: AccessTarget,
|
||||||
|
receiverValues: Map<PseudoValue, ReceiverValue>,
|
||||||
|
private var _outputValue: PseudoValue?
|
||||||
|
) : AccessValueInstruction(element, blockScope, target, receiverValues), InstructionWithValue {
|
||||||
|
constructor(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
target: AccessTarget,
|
target: AccessTarget,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>,
|
receiverValues: Map<PseudoValue, ReceiverValue>,
|
||||||
private var _outputValue: PseudoValue?
|
factory: PseudoValueFactory
|
||||||
) : AccessValueInstruction(element, blockScope, target, receiverValues), InstructionWithValue {
|
) : this(element, blockScope, target, receiverValues, null) {
|
||||||
constructor(
|
|
||||||
element: KtElement,
|
|
||||||
blockScope: BlockScope,
|
|
||||||
target: AccessTarget,
|
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>,
|
|
||||||
factory: PseudoValueFactory
|
|
||||||
): this(element, blockScope, target, receiverValues, null) {
|
|
||||||
_outputValue = factory.newValue(element, this)
|
_outputValue = factory.newValue(element, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,16 +99,16 @@ class ReadValueInstruction private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun createCopy(): InstructionImpl =
|
override fun createCopy(): InstructionImpl =
|
||||||
ReadValueInstruction(element, blockScope, target, receiverValues, outputValue)
|
ReadValueInstruction(element, blockScope, target, receiverValues, outputValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
class WriteValueInstruction(
|
class WriteValueInstruction(
|
||||||
assignment: KtElement,
|
assignment: KtElement,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
target: AccessTarget,
|
target: AccessTarget,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>,
|
receiverValues: Map<PseudoValue, ReceiverValue>,
|
||||||
val lValue: KtElement,
|
val lValue: KtElement,
|
||||||
private val rValue: PseudoValue
|
private val rValue: PseudoValue
|
||||||
) : AccessValueInstruction(assignment, blockScope, target, receiverValues) {
|
) : AccessValueInstruction(assignment, blockScope, target, receiverValues) {
|
||||||
override val inputValues: List<PseudoValue>
|
override val inputValues: List<PseudoValue>
|
||||||
get() = (receiverValues.keys as Collection<PseudoValue>) + rValue
|
get() = (receiverValues.keys as Collection<PseudoValue>) + rValue
|
||||||
@@ -123,5 +125,5 @@ class WriteValueInstruction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun createCopy(): InstructionImpl =
|
override fun createCopy(): InstructionImpl =
|
||||||
WriteValueInstruction(element, blockScope, target, receiverValues, lValue, rValue)
|
WriteValueInstruction(element, blockScope, target, receiverValues, lValue, rValue)
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-41
@@ -28,9 +28,9 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
|||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
|
|
||||||
abstract class OperationInstruction protected constructor(
|
abstract class OperationInstruction protected constructor(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
override val inputValues: List<PseudoValue>
|
override val inputValues: List<PseudoValue>
|
||||||
) : InstructionWithNext(element, blockScope), InstructionWithValue {
|
) : InstructionWithNext(element, blockScope), InstructionWithValue {
|
||||||
protected var resultValue: PseudoValue? = null
|
protected var resultValue: PseudoValue? = null
|
||||||
|
|
||||||
@@ -38,9 +38,9 @@ abstract class OperationInstruction protected constructor(
|
|||||||
get() = resultValue
|
get() = resultValue
|
||||||
|
|
||||||
protected fun renderInstruction(name: String, desc: String): String =
|
protected fun renderInstruction(name: String, desc: String): String =
|
||||||
"$name($desc" +
|
"$name($desc" +
|
||||||
(if (inputValues.isNotEmpty()) "|${inputValues.joinToString(", ")})" else ")") +
|
(if (inputValues.isNotEmpty()) "|${inputValues.joinToString(", ")})" else ")") +
|
||||||
(if (resultValue != null) " -> $resultValue" else "")
|
(if (resultValue != null) " -> $resultValue" else "")
|
||||||
|
|
||||||
protected fun setResult(value: PseudoValue?): OperationInstruction {
|
protected fun setResult(value: PseudoValue?): OperationInstruction {
|
||||||
this.resultValue = value
|
this.resultValue = value
|
||||||
@@ -48,25 +48,25 @@ abstract class OperationInstruction protected constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected fun setResult(factory: PseudoValueFactory?, valueElement: KtElement? = element): OperationInstruction =
|
protected fun setResult(factory: PseudoValueFactory?, valueElement: KtElement? = element): OperationInstruction =
|
||||||
setResult(factory?.newValue(valueElement, this))
|
setResult(factory?.newValue(valueElement, this))
|
||||||
}
|
}
|
||||||
|
|
||||||
class CallInstruction private constructor(
|
class CallInstruction private constructor(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
val resolvedCall: ResolvedCall<*>,
|
val resolvedCall: ResolvedCall<*>,
|
||||||
override val receiverValues: Map<PseudoValue, ReceiverValue>,
|
override val receiverValues: Map<PseudoValue, ReceiverValue>,
|
||||||
val arguments: Map<PseudoValue, ValueParameterDescriptor>
|
val arguments: Map<PseudoValue, ValueParameterDescriptor>
|
||||||
) : OperationInstruction(element, blockScope, (receiverValues.keys as Collection<PseudoValue>) + arguments.keys), InstructionWithReceivers {
|
) : OperationInstruction(element, blockScope, (receiverValues.keys as Collection<PseudoValue>) + arguments.keys), InstructionWithReceivers {
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
resolvedCall: ResolvedCall<*>,
|
resolvedCall: ResolvedCall<*>,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>,
|
receiverValues: Map<PseudoValue, ReceiverValue>,
|
||||||
arguments: Map<PseudoValue, ValueParameterDescriptor>,
|
arguments: Map<PseudoValue, ValueParameterDescriptor>,
|
||||||
factory: PseudoValueFactory?
|
factory: PseudoValueFactory?
|
||||||
): this(element, blockScope, resolvedCall, receiverValues, arguments) {
|
) : this(element, blockScope, resolvedCall, receiverValues, arguments) {
|
||||||
setResult(factory)
|
setResult(factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,10 +77,10 @@ class CallInstruction private constructor(
|
|||||||
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitCallInstruction(this)
|
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitCallInstruction(this)
|
||||||
|
|
||||||
override fun createCopy() =
|
override fun createCopy() =
|
||||||
CallInstruction(element, blockScope, resolvedCall, receiverValues, arguments).setResult(resultValue)
|
CallInstruction(element, blockScope, resolvedCall, receiverValues, arguments).setResult(resultValue)
|
||||||
|
|
||||||
override fun toString() =
|
override fun toString() =
|
||||||
renderInstruction("call", "${render(element)}, ${resolvedCall.resultingDescriptor!!.name}")
|
renderInstruction("call", "${render(element)}, ${resolvedCall.resultingDescriptor!!.name}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Introduces black-box operation
|
// Introduces black-box operation
|
||||||
@@ -89,19 +89,19 @@ class CallInstruction private constructor(
|
|||||||
// denote value transformation which can't be expressed by other instructions (such as call or read)
|
// denote value transformation which can't be expressed by other instructions (such as call or read)
|
||||||
// pass more than one value to instruction which formally requires only one (e.g. jump)
|
// pass more than one value to instruction which formally requires only one (e.g. jump)
|
||||||
class MagicInstruction(
|
class MagicInstruction(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
inputValues: List<PseudoValue>,
|
inputValues: List<PseudoValue>,
|
||||||
val kind: MagicKind
|
val kind: MagicKind
|
||||||
) : OperationInstruction(element, blockScope, inputValues) {
|
) : OperationInstruction(element, blockScope, inputValues) {
|
||||||
constructor (
|
constructor (
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
valueElement: KtElement?,
|
valueElement: KtElement?,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
inputValues: List<PseudoValue>,
|
inputValues: List<PseudoValue>,
|
||||||
kind: MagicKind,
|
kind: MagicKind,
|
||||||
factory: PseudoValueFactory
|
factory: PseudoValueFactory
|
||||||
): this(element, blockScope, inputValues, kind) {
|
) : this(element, blockScope, inputValues, kind) {
|
||||||
setResult(factory, valueElement)
|
setResult(factory, valueElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ class MagicInstruction(
|
|||||||
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitMagic(this)
|
override fun <R> accept(visitor: InstructionVisitorWithResult<R>): R = visitor.visitMagic(this)
|
||||||
|
|
||||||
override fun createCopy() =
|
override fun createCopy() =
|
||||||
MagicInstruction(element, blockScope, inputValues, kind).setResult(resultValue)
|
MagicInstruction(element, blockScope, inputValues, kind).setResult(resultValue)
|
||||||
|
|
||||||
override fun toString() = renderInstruction("magic[$kind]", render(element))
|
override fun toString() = renderInstruction("magic[$kind]", render(element))
|
||||||
}
|
}
|
||||||
@@ -145,16 +145,16 @@ enum class MagicKind(val sideEffectFree: Boolean = false) {
|
|||||||
|
|
||||||
// Merges values produced by alternative control-flow paths (such as 'if' branches)
|
// Merges values produced by alternative control-flow paths (such as 'if' branches)
|
||||||
class MergeInstruction private constructor(
|
class MergeInstruction private constructor(
|
||||||
|
element: KtElement,
|
||||||
|
blockScope: BlockScope,
|
||||||
|
inputValues: List<PseudoValue>
|
||||||
|
) : OperationInstruction(element, blockScope, inputValues) {
|
||||||
|
constructor (
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
inputValues: List<PseudoValue>
|
inputValues: List<PseudoValue>,
|
||||||
): OperationInstruction(element, blockScope, inputValues) {
|
factory: PseudoValueFactory
|
||||||
constructor (
|
) : this(element, blockScope, inputValues) {
|
||||||
element: KtElement,
|
|
||||||
blockScope: BlockScope,
|
|
||||||
inputValues: List<PseudoValue>,
|
|
||||||
factory: PseudoValueFactory
|
|
||||||
): this(element, blockScope, inputValues) {
|
|
||||||
setResult(factory)
|
setResult(factory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -26,11 +26,12 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithRe
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
|
||||||
|
|
||||||
class ConditionalJumpInstruction(
|
class ConditionalJumpInstruction(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
val onTrue: Boolean,
|
val onTrue: Boolean,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
targetLabel: Label,
|
targetLabel: Label,
|
||||||
private val conditionValue: PseudoValue?) : AbstractJumpInstruction(element, targetLabel, blockScope) {
|
private val conditionValue: PseudoValue?
|
||||||
|
) : AbstractJumpInstruction(element, targetLabel, blockScope) {
|
||||||
private var _nextOnTrue: Instruction? = null
|
private var _nextOnTrue: Instruction? = null
|
||||||
private var _nextOnFalse: Instruction? = null
|
private var _nextOnFalse: Instruction? = null
|
||||||
|
|
||||||
@@ -67,5 +68,5 @@ class ConditionalJumpInstruction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction =
|
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction =
|
||||||
ConditionalJumpInstruction(element, onTrue, blockScope, newLabel, conditionValue)
|
ConditionalJumpInstruction(element, onTrue, blockScope, newLabel, conditionValue)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -23,10 +23,10 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
|
||||||
|
|
||||||
class ReturnNoValueInstruction(
|
class ReturnNoValueInstruction(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
targetLabel: Label,
|
targetLabel: Label,
|
||||||
val subroutine: KtElement
|
val subroutine: KtElement
|
||||||
) : AbstractJumpInstruction(element, targetLabel, blockScope) {
|
) : AbstractJumpInstruction(element, targetLabel, blockScope) {
|
||||||
override fun accept(visitor: InstructionVisitor) {
|
override fun accept(visitor: InstructionVisitor) {
|
||||||
visitor.visitReturnNoValue(this)
|
visitor.visitReturnNoValue(this)
|
||||||
@@ -37,5 +37,5 @@ class ReturnNoValueInstruction(
|
|||||||
override fun toString(): String = "ret $targetLabel"
|
override fun toString(): String = "ret $targetLabel"
|
||||||
|
|
||||||
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction =
|
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction =
|
||||||
ReturnNoValueInstruction(element, blockScope, newLabel, subroutine)
|
ReturnNoValueInstruction(element, blockScope, newLabel, subroutine)
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -27,11 +27,11 @@ import org.jetbrains.kotlin.psi.KtElement
|
|||||||
import org.jetbrains.kotlin.psi.KtReturnExpression
|
import org.jetbrains.kotlin.psi.KtReturnExpression
|
||||||
|
|
||||||
class ReturnValueInstruction(
|
class ReturnValueInstruction(
|
||||||
returnExpression: KtExpression,
|
returnExpression: KtExpression,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
targetLabel: Label,
|
targetLabel: Label,
|
||||||
val returnedValue: PseudoValue,
|
val returnedValue: PseudoValue,
|
||||||
val subroutine: KtElement
|
val subroutine: KtElement
|
||||||
) : AbstractJumpInstruction(returnExpression, targetLabel, blockScope) {
|
) : AbstractJumpInstruction(returnExpression, targetLabel, blockScope) {
|
||||||
override val inputValues: List<PseudoValue> get() = Collections.singletonList(returnedValue)
|
override val inputValues: List<PseudoValue> get() = Collections.singletonList(returnedValue)
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ class ReturnValueInstruction(
|
|||||||
override fun toString(): String = "ret(*|$returnedValue) $targetLabel"
|
override fun toString(): String = "ret(*|$returnedValue) $targetLabel"
|
||||||
|
|
||||||
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction =
|
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction =
|
||||||
ReturnValueInstruction((element as KtExpression), blockScope, newLabel, returnedValue, subroutine)
|
ReturnValueInstruction((element as KtExpression), blockScope, newLabel, returnedValue, subroutine)
|
||||||
|
|
||||||
val returnExpressionIfAny: KtReturnExpression? = element as? KtReturnExpression
|
val returnExpressionIfAny: KtReturnExpression? = element as? KtReturnExpression
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -25,10 +25,10 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
|
||||||
|
|
||||||
class ThrowExceptionInstruction(
|
class ThrowExceptionInstruction(
|
||||||
expression: KtThrowExpression,
|
expression: KtThrowExpression,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
errorLabel: Label,
|
errorLabel: Label,
|
||||||
private val thrownValue: PseudoValue
|
private val thrownValue: PseudoValue
|
||||||
) : AbstractJumpInstruction(expression, errorLabel, blockScope) {
|
) : AbstractJumpInstruction(expression, errorLabel, blockScope) {
|
||||||
override val inputValues: List<PseudoValue> get() = Collections.singletonList(thrownValue)
|
override val inputValues: List<PseudoValue> get() = Collections.singletonList(thrownValue)
|
||||||
|
|
||||||
@@ -41,5 +41,5 @@ class ThrowExceptionInstruction(
|
|||||||
override fun toString(): String = "throw (${element.text}|$thrownValue)"
|
override fun toString(): String = "throw (${element.text}|$thrownValue)"
|
||||||
|
|
||||||
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction =
|
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction =
|
||||||
ThrowExceptionInstruction((element as KtThrowExpression), blockScope, newLabel, thrownValue)
|
ThrowExceptionInstruction((element as KtThrowExpression), blockScope, newLabel, thrownValue)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -21,9 +21,9 @@ import org.jetbrains.kotlin.psi.KtElement
|
|||||||
import org.jetbrains.kotlin.cfg.Label
|
import org.jetbrains.kotlin.cfg.Label
|
||||||
|
|
||||||
class UnconditionalJumpInstruction(
|
class UnconditionalJumpInstruction(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
targetLabel: Label,
|
targetLabel: Label,
|
||||||
blockScope: BlockScope
|
blockScope: BlockScope
|
||||||
) : AbstractJumpInstruction(element, targetLabel, blockScope) {
|
) : AbstractJumpInstruction(element, targetLabel, blockScope) {
|
||||||
override fun accept(visitor: InstructionVisitor) {
|
override fun accept(visitor: InstructionVisitor) {
|
||||||
visitor.visitUnconditionalJump(this)
|
visitor.visitUnconditionalJump(this)
|
||||||
@@ -34,5 +34,5 @@ class UnconditionalJumpInstruction(
|
|||||||
override fun toString(): String = "jmp(${targetLabel.name})"
|
override fun toString(): String = "jmp(${targetLabel.name})"
|
||||||
|
|
||||||
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction =
|
override fun createCopy(newLabel: Label, blockScope: BlockScope): AbstractJumpInstruction =
|
||||||
UnconditionalJumpInstruction(element, newLabel, blockScope)
|
UnconditionalJumpInstruction(element, newLabel, blockScope)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -25,10 +25,10 @@ import org.jetbrains.kotlin.contracts.description.InvocationKind
|
|||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
|
||||||
class InlinedLocalFunctionDeclarationInstruction(
|
class InlinedLocalFunctionDeclarationInstruction(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
body: Pseudocode,
|
body: Pseudocode,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
val kind: InvocationKind
|
val kind: InvocationKind
|
||||||
) : LocalFunctionDeclarationInstruction(element, body, blockScope) {
|
) : LocalFunctionDeclarationInstruction(element, body, blockScope) {
|
||||||
override fun createCopy(): InstructionImpl = InlinedLocalFunctionDeclarationInstruction(element, body, blockScope, kind)
|
override fun createCopy(): InstructionImpl = InlinedLocalFunctionDeclarationInstruction(element, body, blockScope, kind)
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -26,9 +26,9 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithRe
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
|
||||||
|
|
||||||
open class LocalFunctionDeclarationInstruction(
|
open class LocalFunctionDeclarationInstruction(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
val body: Pseudocode,
|
val body: Pseudocode,
|
||||||
blockScope: BlockScope
|
blockScope: BlockScope
|
||||||
) : InstructionWithNext(element, blockScope) {
|
) : InstructionWithNext(element, blockScope) {
|
||||||
var sink: SubroutineSinkInstruction? = null
|
var sink: SubroutineSinkInstruction? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
@@ -54,5 +54,5 @@ open class LocalFunctionDeclarationInstruction(
|
|||||||
override fun toString(): String = "d(${render(element)})"
|
override fun toString(): String = "d(${render(element)})"
|
||||||
|
|
||||||
override fun createCopy(): InstructionImpl =
|
override fun createCopy(): InstructionImpl =
|
||||||
LocalFunctionDeclarationInstruction(element, body.copy(), blockScope)
|
LocalFunctionDeclarationInstruction(element, body.copy(), blockScope)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -23,8 +23,8 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
|
||||||
|
|
||||||
class MarkInstruction(
|
class MarkInstruction(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
blockScope: BlockScope
|
blockScope: BlockScope
|
||||||
) : InstructionWithNext(element, blockScope) {
|
) : InstructionWithNext(element, blockScope) {
|
||||||
|
|
||||||
override fun accept(visitor: InstructionVisitor) {
|
override fun accept(visitor: InstructionVisitor) {
|
||||||
|
|||||||
+3
-3
@@ -24,8 +24,8 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithRe
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
|
||||||
|
|
||||||
class SubroutineEnterInstruction(
|
class SubroutineEnterInstruction(
|
||||||
val subroutine: KtElement,
|
val subroutine: KtElement,
|
||||||
blockScope: BlockScope
|
blockScope: BlockScope
|
||||||
) : InstructionWithNext(subroutine, blockScope) {
|
) : InstructionWithNext(subroutine, blockScope) {
|
||||||
override fun accept(visitor: InstructionVisitor) {
|
override fun accept(visitor: InstructionVisitor) {
|
||||||
visitor.visitSubroutineEnter(this)
|
visitor.visitSubroutineEnter(this)
|
||||||
@@ -36,5 +36,5 @@ class SubroutineEnterInstruction(
|
|||||||
override fun toString(): String = "<START>"
|
override fun toString(): String = "<START>"
|
||||||
|
|
||||||
override fun createCopy(): InstructionImpl =
|
override fun createCopy(): InstructionImpl =
|
||||||
SubroutineEnterInstruction(subroutine, blockScope)
|
SubroutineEnterInstruction(subroutine, blockScope)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -21,9 +21,9 @@ import org.jetbrains.kotlin.psi.KtElement
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class SubroutineExitInstruction(
|
class SubroutineExitInstruction(
|
||||||
val subroutine: KtElement,
|
val subroutine: KtElement,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
val isError: Boolean
|
val isError: Boolean
|
||||||
) : InstructionImpl(blockScope) {
|
) : InstructionImpl(blockScope) {
|
||||||
private var _sink: SubroutineSinkInstruction? = null
|
private var _sink: SubroutineSinkInstruction? = null
|
||||||
|
|
||||||
@@ -45,5 +45,5 @@ class SubroutineExitInstruction(
|
|||||||
override fun toString(): String = if (isError) "<ERROR>" else "<END>"
|
override fun toString(): String = if (isError) "<ERROR>" else "<END>"
|
||||||
|
|
||||||
override fun createCopy(): InstructionImpl =
|
override fun createCopy(): InstructionImpl =
|
||||||
SubroutineExitInstruction(subroutine, blockScope, isError)
|
SubroutineExitInstruction(subroutine, blockScope, isError)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-4
@@ -25,9 +25,10 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
|
||||||
|
|
||||||
class SubroutineSinkInstruction(
|
class SubroutineSinkInstruction(
|
||||||
val subroutine: KtElement,
|
val subroutine: KtElement,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
private val debugLabel: String) : InstructionImpl(blockScope) {
|
private val debugLabel: String
|
||||||
|
) : InstructionImpl(blockScope) {
|
||||||
override val nextInstructions: Collection<Instruction>
|
override val nextInstructions: Collection<Instruction>
|
||||||
get() = Collections.emptyList()
|
get() = Collections.emptyList()
|
||||||
|
|
||||||
@@ -40,5 +41,5 @@ class SubroutineSinkInstruction(
|
|||||||
override fun toString(): String = debugLabel
|
override fun toString(): String = debugLabel
|
||||||
|
|
||||||
override fun createCopy(): InstructionImpl =
|
override fun createCopy(): InstructionImpl =
|
||||||
SubroutineSinkInstruction(subroutine, blockScope, debugLabel)
|
SubroutineSinkInstruction(subroutine, blockScope, debugLabel)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -24,8 +24,8 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
|
||||||
class VariableDeclarationInstruction(
|
class VariableDeclarationInstruction(
|
||||||
element: KtDeclaration,
|
element: KtDeclaration,
|
||||||
blockScope: BlockScope
|
blockScope: BlockScope
|
||||||
) : InstructionWithNext(element, blockScope) {
|
) : InstructionWithNext(element, blockScope) {
|
||||||
init {
|
init {
|
||||||
assert(element is KtVariableDeclaration || element is KtParameter || element is KtEnumEntry || element is KtObjectDeclaration) {
|
assert(element is KtVariableDeclaration || element is KtParameter || element is KtEnumEntry || element is KtObjectDeclaration) {
|
||||||
@@ -45,5 +45,5 @@ class VariableDeclarationInstruction(
|
|||||||
override fun toString(): String = "v(${render(element)})"
|
override fun toString(): String = "v(${render(element)})"
|
||||||
|
|
||||||
override fun createCopy(): InstructionImpl =
|
override fun createCopy(): InstructionImpl =
|
||||||
VariableDeclarationInstruction(variableDeclarationElement, blockScope)
|
VariableDeclarationInstruction(variableDeclarationElement, blockScope)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ interface ModuleContext : ProjectContext {
|
|||||||
val module: ModuleDescriptor
|
val module: ModuleDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MutableModuleContext: ModuleContext {
|
interface MutableModuleContext : ModuleContext {
|
||||||
override val module: ModuleDescriptorImpl
|
override val module: ModuleDescriptorImpl
|
||||||
|
|
||||||
fun setDependencies(vararg dependencies: ModuleDescriptorImpl) {
|
fun setDependencies(vararg dependencies: ModuleDescriptorImpl) {
|
||||||
@@ -57,30 +57,30 @@ interface MutableModuleContext: ModuleContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open class SimpleGlobalContext(
|
open class SimpleGlobalContext(
|
||||||
override val storageManager: StorageManager,
|
override val storageManager: StorageManager,
|
||||||
override val exceptionTracker: ExceptionTracker
|
override val exceptionTracker: ExceptionTracker
|
||||||
) : GlobalContext
|
) : GlobalContext
|
||||||
|
|
||||||
open class GlobalContextImpl(
|
open class GlobalContextImpl(
|
||||||
storageManager: LockBasedStorageManager,
|
storageManager: LockBasedStorageManager,
|
||||||
exceptionTracker: ExceptionTracker
|
exceptionTracker: ExceptionTracker
|
||||||
) : SimpleGlobalContext(storageManager, exceptionTracker) {
|
) : SimpleGlobalContext(storageManager, exceptionTracker) {
|
||||||
override val storageManager: LockBasedStorageManager = super.storageManager as LockBasedStorageManager
|
override val storageManager: LockBasedStorageManager = super.storageManager as LockBasedStorageManager
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProjectContextImpl(
|
class ProjectContextImpl(
|
||||||
override val project: Project,
|
override val project: Project,
|
||||||
private val globalContext: GlobalContext
|
private val globalContext: GlobalContext
|
||||||
) : ProjectContext, GlobalContext by globalContext
|
) : ProjectContext, GlobalContext by globalContext
|
||||||
|
|
||||||
class ModuleContextImpl(
|
class ModuleContextImpl(
|
||||||
override val module: ModuleDescriptor,
|
override val module: ModuleDescriptor,
|
||||||
projectContext: ProjectContext
|
projectContext: ProjectContext
|
||||||
) : ModuleContext, ProjectContext by projectContext
|
) : ModuleContext, ProjectContext by projectContext
|
||||||
|
|
||||||
class MutableModuleContextImpl(
|
class MutableModuleContextImpl(
|
||||||
override val module: ModuleDescriptorImpl,
|
override val module: ModuleDescriptorImpl,
|
||||||
projectContext: ProjectContext
|
projectContext: ProjectContext
|
||||||
) : MutableModuleContext, ProjectContext by projectContext
|
) : MutableModuleContext, ProjectContext by projectContext
|
||||||
|
|
||||||
fun GlobalContext(): GlobalContextImpl {
|
fun GlobalContext(): GlobalContextImpl {
|
||||||
@@ -90,16 +90,16 @@ fun GlobalContext(): GlobalContextImpl {
|
|||||||
|
|
||||||
fun ProjectContext(project: Project): ProjectContext = ProjectContextImpl(project, GlobalContext())
|
fun ProjectContext(project: Project): ProjectContext = ProjectContextImpl(project, GlobalContext())
|
||||||
fun ModuleContext(module: ModuleDescriptor, project: Project): ModuleContext =
|
fun ModuleContext(module: ModuleDescriptor, project: Project): ModuleContext =
|
||||||
ModuleContextImpl(module, ProjectContext(project))
|
ModuleContextImpl(module, ProjectContext(project))
|
||||||
|
|
||||||
fun GlobalContext.withProject(project: Project): ProjectContext = ProjectContextImpl(project, this)
|
fun GlobalContext.withProject(project: Project): ProjectContext = ProjectContextImpl(project, this)
|
||||||
fun ProjectContext.withModule(module: ModuleDescriptor): ModuleContext = ModuleContextImpl(module, this)
|
fun ProjectContext.withModule(module: ModuleDescriptor): ModuleContext = ModuleContextImpl(module, this)
|
||||||
|
|
||||||
fun ContextForNewModule(
|
fun ContextForNewModule(
|
||||||
projectContext: ProjectContext,
|
projectContext: ProjectContext,
|
||||||
moduleName: Name,
|
moduleName: Name,
|
||||||
builtIns: KotlinBuiltIns,
|
builtIns: KotlinBuiltIns,
|
||||||
multiTargetPlatform: MultiTargetPlatform?
|
multiTargetPlatform: MultiTargetPlatform?
|
||||||
): MutableModuleContext {
|
): MutableModuleContext {
|
||||||
val module = ModuleDescriptorImpl(moduleName, projectContext.storageManager, builtIns, multiTargetPlatform)
|
val module = ModuleDescriptorImpl(moduleName, projectContext.storageManager, builtIns, multiTargetPlatform)
|
||||||
return MutableModuleContextImpl(module, projectContext)
|
return MutableModuleContextImpl(module, projectContext)
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ import org.jetbrains.kotlin.utils.addIfNotNull
|
|||||||
|
|
||||||
class ContractDeserializerImpl(private val configuration: DeserializationConfiguration) : ContractDeserializer {
|
class ContractDeserializerImpl(private val configuration: DeserializationConfiguration) : ContractDeserializer {
|
||||||
override fun deserializeContractFromFunction(
|
override fun deserializeContractFromFunction(
|
||||||
proto: ProtoBuf.Function,
|
proto: ProtoBuf.Function,
|
||||||
ownerFunction: FunctionDescriptor,
|
ownerFunction: FunctionDescriptor,
|
||||||
typeTable: TypeTable,
|
typeTable: TypeTable,
|
||||||
typeDeserializer: TypeDeserializer
|
typeDeserializer: TypeDeserializer
|
||||||
): Pair<FunctionDescriptor.UserDataKey<*>, LazyContractProvider>? {
|
): Pair<FunctionDescriptor.UserDataKey<*>, LazyContractProvider>? {
|
||||||
if (!proto.hasContract()) return null
|
if (!proto.hasContract()) return null
|
||||||
|
|
||||||
@@ -46,9 +46,9 @@ class ContractDeserializerImpl(private val configuration: DeserializationConfigu
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class ContractDeserializationWorker(
|
private class ContractDeserializationWorker(
|
||||||
private val typeTable: TypeTable,
|
private val typeTable: TypeTable,
|
||||||
private val typeDeserializer: TypeDeserializer,
|
private val typeDeserializer: TypeDeserializer,
|
||||||
private val ownerFunction: FunctionDescriptor
|
private val ownerFunction: FunctionDescriptor
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun deserializeContract(proto: ProtoBuf.Contract): ContractDescription? {
|
fun deserializeContract(proto: ProtoBuf.Contract): ContractDescription? {
|
||||||
@@ -71,7 +71,9 @@ class ContractDeserializerImpl(private val configuration: DeserializationConfigu
|
|||||||
return when (type!!) {
|
return when (type!!) {
|
||||||
ProtoBuf.Effect.EffectType.RETURNS_CONSTANT -> {
|
ProtoBuf.Effect.EffectType.RETURNS_CONSTANT -> {
|
||||||
val argument = proto.effectConstructorArgumentList.getOrNull(0)
|
val argument = proto.effectConstructorArgumentList.getOrNull(0)
|
||||||
val returnValue = if (argument == null) ConstantReference.WILDCARD else deserializeExpression(argument) as? ConstantReference ?: return null
|
val returnValue =
|
||||||
|
if (argument == null) ConstantReference.WILDCARD else deserializeExpression(argument) as? ConstantReference
|
||||||
|
?: return null
|
||||||
ReturnsEffectDeclaration(returnValue)
|
ReturnsEffectDeclaration(returnValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +227,7 @@ class ContractDeserializerImpl(private val configuration: DeserializationConfigu
|
|||||||
private fun ProtoBuf.Expression.hasType(): Boolean = this.hasIsInstanceType() || this.hasIsInstanceTypeId()
|
private fun ProtoBuf.Expression.hasType(): Boolean = this.hasIsInstanceType() || this.hasIsInstanceTypeId()
|
||||||
|
|
||||||
private fun ProtoBuf.Expression.hasFlag(flag: Flags.BooleanFlagField) =
|
private fun ProtoBuf.Expression.hasFlag(flag: Flags.BooleanFlagField) =
|
||||||
this.hasFlags() && flag.get(this.flags)
|
this.hasFlags() && flag.get(this.flags)
|
||||||
|
|
||||||
// Arguments of expressions with such types are never other expressions
|
// Arguments of expressions with such types are never other expressions
|
||||||
private enum class PrimitiveExpressionType {
|
private enum class PrimitiveExpressionType {
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
|||||||
class EffectSystem(val languageVersionSettings: LanguageVersionSettings) {
|
class EffectSystem(val languageVersionSettings: LanguageVersionSettings) {
|
||||||
|
|
||||||
fun getDataFlowInfoForFinishedCall(
|
fun getDataFlowInfoForFinishedCall(
|
||||||
resolvedCall: ResolvedCall<*>,
|
resolvedCall: ResolvedCall<*>,
|
||||||
bindingTrace: BindingTrace,
|
bindingTrace: BindingTrace,
|
||||||
moduleDescriptor: ModuleDescriptor
|
moduleDescriptor: ModuleDescriptor
|
||||||
): DataFlowInfo {
|
): DataFlowInfo {
|
||||||
if (!languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)) return DataFlowInfo.EMPTY
|
if (!languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)) return DataFlowInfo.EMPTY
|
||||||
|
|
||||||
@@ -57,16 +57,18 @@ class EffectSystem(val languageVersionSettings: LanguageVersionSettings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getDataFlowInfoWhenEquals(
|
fun getDataFlowInfoWhenEquals(
|
||||||
leftExpression: KtExpression?,
|
leftExpression: KtExpression?,
|
||||||
rightExpression: KtExpression?,
|
rightExpression: KtExpression?,
|
||||||
bindingTrace: BindingTrace,
|
bindingTrace: BindingTrace,
|
||||||
moduleDescriptor: ModuleDescriptor
|
moduleDescriptor: ModuleDescriptor
|
||||||
): ConditionalDataFlowInfo {
|
): ConditionalDataFlowInfo {
|
||||||
if (!languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)) return ConditionalDataFlowInfo.EMPTY
|
if (!languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)) return ConditionalDataFlowInfo.EMPTY
|
||||||
if (leftExpression == null || rightExpression == null) return ConditionalDataFlowInfo.EMPTY
|
if (leftExpression == null || rightExpression == null) return ConditionalDataFlowInfo.EMPTY
|
||||||
|
|
||||||
val leftComputation = getNonTrivialComputation(leftExpression, bindingTrace, moduleDescriptor) ?: return ConditionalDataFlowInfo.EMPTY
|
val leftComputation =
|
||||||
val rightComputation = getNonTrivialComputation(rightExpression, bindingTrace, moduleDescriptor) ?: return ConditionalDataFlowInfo.EMPTY
|
getNonTrivialComputation(leftExpression, bindingTrace, moduleDescriptor) ?: return ConditionalDataFlowInfo.EMPTY
|
||||||
|
val rightComputation =
|
||||||
|
getNonTrivialComputation(rightExpression, bindingTrace, moduleDescriptor) ?: return ConditionalDataFlowInfo.EMPTY
|
||||||
|
|
||||||
val effects = EqualsFunctor(false).invokeWithArguments(leftComputation, rightComputation)
|
val effects = EqualsFunctor(false).invokeWithArguments(leftComputation, rightComputation)
|
||||||
|
|
||||||
@@ -74,8 +76,8 @@ class EffectSystem(val languageVersionSettings: LanguageVersionSettings) {
|
|||||||
val notEqualsContextInfo = InfoCollector(ESReturns(false.lift())).collectFromSchema(effects)
|
val notEqualsContextInfo = InfoCollector(ESReturns(false.lift())).collectFromSchema(effects)
|
||||||
|
|
||||||
return ConditionalDataFlowInfo(
|
return ConditionalDataFlowInfo(
|
||||||
equalsContextInfo.toDataFlowInfo(languageVersionSettings),
|
equalsContextInfo.toDataFlowInfo(languageVersionSettings),
|
||||||
notEqualsContextInfo.toDataFlowInfo(languageVersionSettings)
|
notEqualsContextInfo.toDataFlowInfo(languageVersionSettings)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,23 +97,23 @@ class EffectSystem(val languageVersionSettings: LanguageVersionSettings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun extractDataFlowInfoFromCondition(
|
fun extractDataFlowInfoFromCondition(
|
||||||
condition: KtExpression?,
|
condition: KtExpression?,
|
||||||
value: Boolean,
|
value: Boolean,
|
||||||
bindingTrace: BindingTrace,
|
bindingTrace: BindingTrace,
|
||||||
moduleDescriptor: ModuleDescriptor
|
moduleDescriptor: ModuleDescriptor
|
||||||
): DataFlowInfo {
|
): DataFlowInfo {
|
||||||
if (!languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)) return DataFlowInfo.EMPTY
|
if (!languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect)) return DataFlowInfo.EMPTY
|
||||||
if (condition == null) return DataFlowInfo.EMPTY
|
if (condition == null) return DataFlowInfo.EMPTY
|
||||||
|
|
||||||
return getContextInfoWhen(ESReturns(value.lift()), condition, bindingTrace, moduleDescriptor)
|
return getContextInfoWhen(ESReturns(value.lift()), condition, bindingTrace, moduleDescriptor)
|
||||||
.toDataFlowInfo(languageVersionSettings)
|
.toDataFlowInfo(languageVersionSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getContextInfoWhen(
|
private fun getContextInfoWhen(
|
||||||
observedEffect: ESEffect,
|
observedEffect: ESEffect,
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
bindingTrace: BindingTrace,
|
bindingTrace: BindingTrace,
|
||||||
moduleDescriptor: ModuleDescriptor
|
moduleDescriptor: ModuleDescriptor
|
||||||
): MutableContextInfo {
|
): MutableContextInfo {
|
||||||
val computation = getNonTrivialComputation(expression, bindingTrace, moduleDescriptor) ?: return MutableContextInfo.EMPTY
|
val computation = getNonTrivialComputation(expression, bindingTrace, moduleDescriptor) ?: return MutableContextInfo.EMPTY
|
||||||
return InfoCollector(observedEffect).collectFromSchema(computation.effects)
|
return InfoCollector(observedEffect).collectFromSchema(computation.effects)
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ import org.jetbrains.kotlin.utils.addIfNotNull
|
|||||||
* about effects of that call.
|
* about effects of that call.
|
||||||
*/
|
*/
|
||||||
class EffectsExtractingVisitor(
|
class EffectsExtractingVisitor(
|
||||||
private val trace: BindingTrace,
|
private val trace: BindingTrace,
|
||||||
private val moduleDescriptor: ModuleDescriptor
|
private val moduleDescriptor: ModuleDescriptor
|
||||||
) : KtVisitor<Computation, Unit>() {
|
) : KtVisitor<Computation, Unit>() {
|
||||||
fun extractOrGetCached(element: KtElement): Computation {
|
fun extractOrGetCached(element: KtElement): Computation {
|
||||||
trace[BindingContext.EXPRESSION_EFFECTS, element]?.let { return it }
|
trace[BindingContext.EXPRESSION_EFFECTS, element]?.let { return it }
|
||||||
@@ -66,9 +66,18 @@ class EffectsExtractingVisitor(
|
|||||||
|
|
||||||
val descriptor = resolvedCall.resultingDescriptor
|
val descriptor = resolvedCall.resultingDescriptor
|
||||||
return when {
|
return when {
|
||||||
descriptor.isEqualsDescriptor() -> CallComputation(DefaultBuiltIns.Instance.booleanType, EqualsFunctor(false).invokeWithArguments(arguments))
|
descriptor.isEqualsDescriptor() -> CallComputation(
|
||||||
descriptor is ValueDescriptor -> ESDataFlowValue(descriptor, (element as KtExpression).createDataFlowValue() ?: return UNKNOWN_COMPUTATION)
|
DefaultBuiltIns.Instance.booleanType,
|
||||||
descriptor is FunctionDescriptor -> CallComputation(descriptor.returnType, descriptor.getFunctor()?.invokeWithArguments(arguments) ?: emptyList())
|
EqualsFunctor(false).invokeWithArguments(arguments)
|
||||||
|
)
|
||||||
|
descriptor is ValueDescriptor -> ESDataFlowValue(
|
||||||
|
descriptor,
|
||||||
|
(element as KtExpression).createDataFlowValue() ?: return UNKNOWN_COMPUTATION
|
||||||
|
)
|
||||||
|
descriptor is FunctionDescriptor -> CallComputation(
|
||||||
|
descriptor.returnType,
|
||||||
|
descriptor.getFunctor()?.invokeWithArguments(arguments) ?: emptyList()
|
||||||
|
)
|
||||||
else -> UNKNOWN_COMPUTATION
|
else -> UNKNOWN_COMPUTATION
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,15 +87,15 @@ class EffectsExtractingVisitor(
|
|||||||
override fun visitLambdaExpression(expression: KtLambdaExpression, data: Unit?): Computation = UNKNOWN_COMPUTATION
|
override fun visitLambdaExpression(expression: KtLambdaExpression, data: Unit?): Computation = UNKNOWN_COMPUTATION
|
||||||
|
|
||||||
override fun visitParenthesizedExpression(expression: KtParenthesizedExpression, data: Unit): Computation =
|
override fun visitParenthesizedExpression(expression: KtParenthesizedExpression, data: Unit): Computation =
|
||||||
KtPsiUtil.deparenthesize(expression)?.accept(this, data) ?: UNKNOWN_COMPUTATION
|
KtPsiUtil.deparenthesize(expression)?.accept(this, data) ?: UNKNOWN_COMPUTATION
|
||||||
|
|
||||||
override fun visitConstantExpression(expression: KtConstantExpression, data: Unit): Computation {
|
override fun visitConstantExpression(expression: KtConstantExpression, data: Unit): Computation {
|
||||||
val bindingContext = trace.bindingContext
|
val bindingContext = trace.bindingContext
|
||||||
|
|
||||||
val type: KotlinType = bindingContext.getType(expression) ?: return UNKNOWN_COMPUTATION
|
val type: KotlinType = bindingContext.getType(expression) ?: return UNKNOWN_COMPUTATION
|
||||||
|
|
||||||
val compileTimeConstant: CompileTimeConstant<*>
|
val compileTimeConstant: CompileTimeConstant<*> =
|
||||||
= bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expression) ?: return UNKNOWN_COMPUTATION
|
bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expression) ?: return UNKNOWN_COMPUTATION
|
||||||
val value: Any? = compileTimeConstant.getValue(type)
|
val value: Any? = compileTimeConstant.getValue(type)
|
||||||
|
|
||||||
return when (value) {
|
return when (value) {
|
||||||
@@ -99,7 +108,10 @@ class EffectsExtractingVisitor(
|
|||||||
override fun visitIsExpression(expression: KtIsExpression, data: Unit): Computation {
|
override fun visitIsExpression(expression: KtIsExpression, data: Unit): Computation {
|
||||||
val rightType: KotlinType = trace[BindingContext.TYPE, expression.typeReference] ?: return UNKNOWN_COMPUTATION
|
val rightType: KotlinType = trace[BindingContext.TYPE, expression.typeReference] ?: return UNKNOWN_COMPUTATION
|
||||||
val arg = extractOrGetCached(expression.leftHandSide)
|
val arg = extractOrGetCached(expression.leftHandSide)
|
||||||
return CallComputation(DefaultBuiltIns.Instance.booleanType, IsFunctor(rightType, expression.isNegated).invokeWithArguments(listOf(arg)))
|
return CallComputation(
|
||||||
|
DefaultBuiltIns.Instance.booleanType,
|
||||||
|
IsFunctor(rightType, expression.isNegated).invokeWithArguments(listOf(arg))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBinaryExpression(expression: KtBinaryExpression, data: Unit): Computation {
|
override fun visitBinaryExpression(expression: KtBinaryExpression, data: Unit): Computation {
|
||||||
@@ -132,10 +144,10 @@ class EffectsExtractingVisitor(
|
|||||||
|
|
||||||
private fun KtExpression.createDataFlowValue(): DataFlowValue? {
|
private fun KtExpression.createDataFlowValue(): DataFlowValue? {
|
||||||
return DataFlowValueFactory.createDataFlowValue(
|
return DataFlowValueFactory.createDataFlowValue(
|
||||||
expression = this,
|
expression = this,
|
||||||
type = trace.getType(this) ?: return null,
|
type = trace.getType(this) ?: return null,
|
||||||
bindingContext = trace.bindingContext,
|
bindingContext = trace.bindingContext,
|
||||||
containingDeclarationOrModule = moduleDescriptor
|
containingDeclarationOrModule = moduleDescriptor
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,9 +160,9 @@ class EffectsExtractingVisitor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ResolvedCall<*>.isCallWithUnsupportedReceiver(): Boolean =
|
private fun ResolvedCall<*>.isCallWithUnsupportedReceiver(): Boolean =
|
||||||
(extensionReceiver as? ExpressionReceiver)?.expression?.getResolvedCall(trace.bindingContext) == this ||
|
(extensionReceiver as? ExpressionReceiver)?.expression?.getResolvedCall(trace.bindingContext) == this ||
|
||||||
(dispatchReceiver as? ExpressionReceiver)?.expression?.getResolvedCall(trace.bindingContext) == this ||
|
(dispatchReceiver as? ExpressionReceiver)?.expression?.getResolvedCall(trace.bindingContext) == this ||
|
||||||
(explicitReceiverKind == ExplicitReceiverKind.BOTH_RECEIVERS)
|
(explicitReceiverKind == ExplicitReceiverKind.BOTH_RECEIVERS)
|
||||||
|
|
||||||
private fun ResolvedCall<*>.getCallArgumentsAsComputations(): List<Computation>? {
|
private fun ResolvedCall<*>.getCallArgumentsAsComputations(): List<Computation>? {
|
||||||
val arguments = mutableListOf<Computation>()
|
val arguments = mutableListOf<Computation>()
|
||||||
|
|||||||
@@ -32,8 +32,7 @@ internal class PsiConstantParser(val trace: BindingTrace) : KtVisitor<ConstantRe
|
|||||||
override fun visitConstantExpression(expression: KtConstantExpression, data: Unit?): ConstantReference? {
|
override fun visitConstantExpression(expression: KtConstantExpression, data: Unit?): ConstantReference? {
|
||||||
val type: KotlinType = trace.getType(expression) ?: return null
|
val type: KotlinType = trace.getType(expression) ?: return null
|
||||||
|
|
||||||
val compileTimeConstant: CompileTimeConstant<*>
|
val compileTimeConstant: CompileTimeConstant<*> = trace.get(BindingContext.COMPILE_TIME_VALUE, expression) ?: return null
|
||||||
= trace.get(BindingContext.COMPILE_TIME_VALUE, expression) ?: return null
|
|
||||||
val value: Any? = compileTimeConstant.getValue(type)
|
val value: Any? = compileTimeConstant.getValue(type)
|
||||||
|
|
||||||
return when (value) {
|
return when (value) {
|
||||||
|
|||||||
+16
-6
@@ -46,10 +46,10 @@ internal class PsiContractParserDispatcher(val trace: BindingTrace, val contract
|
|||||||
private val conditionParser = PsiConditionParser(trace, this)
|
private val conditionParser = PsiConditionParser(trace, this)
|
||||||
private val constantParser = PsiConstantParser(trace)
|
private val constantParser = PsiConstantParser(trace)
|
||||||
private val effectsParsers: Map<Name, PsiEffectParser> = mapOf(
|
private val effectsParsers: Map<Name, PsiEffectParser> = mapOf(
|
||||||
RETURNS_EFFECT to PsiReturnsEffectParser(trace, this),
|
RETURNS_EFFECT to PsiReturnsEffectParser(trace, this),
|
||||||
RETURNS_NOT_NULL_EFFECT to PsiReturnsEffectParser(trace, this),
|
RETURNS_NOT_NULL_EFFECT to PsiReturnsEffectParser(trace, this),
|
||||||
CALLS_IN_PLACE_EFFECT to PsiCallsEffectParser(trace, this),
|
CALLS_IN_PLACE_EFFECT to PsiCallsEffectParser(trace, this),
|
||||||
CONDITIONAL_EFFECT to PsiConditionalEffectParser(trace, this)
|
CONDITIONAL_EFFECT to PsiConditionalEffectParser(trace, this)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun parseContract(expression: KtExpression?, ownerDescriptor: FunctionDescriptor): ContractDescription? {
|
fun parseContract(expression: KtExpression?, ownerDescriptor: FunctionDescriptor): ContractDescription? {
|
||||||
@@ -89,12 +89,22 @@ internal class PsiContractParserDispatcher(val trace: BindingTrace, val contract
|
|||||||
if (expression == null) return null
|
if (expression == null) return null
|
||||||
val descriptor = expression.getResolvedCall(trace.bindingContext)?.resultingDescriptor ?: return null
|
val descriptor = expression.getResolvedCall(trace.bindingContext)?.resultingDescriptor ?: return null
|
||||||
if (descriptor !is ParameterDescriptor) {
|
if (descriptor !is ParameterDescriptor) {
|
||||||
trace.report(Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(expression, "only references to parameters are allowed in contract description"))
|
trace.report(
|
||||||
|
Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(
|
||||||
|
expression,
|
||||||
|
"only references to parameters are allowed in contract description"
|
||||||
|
)
|
||||||
|
)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (descriptor is ReceiverParameterDescriptor && descriptor.type.constructor.declarationDescriptor?.isFromContractDsl() == true) {
|
if (descriptor is ReceiverParameterDescriptor && descriptor.type.constructor.declarationDescriptor?.isFromContractDsl() == true) {
|
||||||
trace.report(Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(expression, "only references to parameters are allowed. Did you miss label on <this>?"))
|
trace.report(
|
||||||
|
Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(
|
||||||
|
expression,
|
||||||
|
"only references to parameters are allowed. Did you miss label on <this>?"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (KotlinBuiltIns.isBoolean(descriptor.type))
|
return if (KotlinBuiltIns.isBoolean(descriptor.type))
|
||||||
|
|||||||
@@ -83,10 +83,10 @@ fun DeclarationDescriptor.isCallsInPlaceEffectDescriptor(): Boolean = equalsDslD
|
|||||||
fun DeclarationDescriptor.isInvocationKindEnum(): Boolean = equalsDslDescriptor(INVOCATION_KIND_ENUM)
|
fun DeclarationDescriptor.isInvocationKindEnum(): Boolean = equalsDslDescriptor(INVOCATION_KIND_ENUM)
|
||||||
|
|
||||||
fun DeclarationDescriptor.isEqualsDescriptor(): Boolean =
|
fun DeclarationDescriptor.isEqualsDescriptor(): Boolean =
|
||||||
this is FunctionDescriptor && this.name == Name.identifier("equals") && // fast checks
|
this is FunctionDescriptor && this.name == Name.identifier("equals") && // fast checks
|
||||||
this.returnType?.isBoolean() == true && this.valueParameters.singleOrNull()?.type?.isNullableAny() == true // signature matches
|
this.returnType?.isBoolean() == true && this.valueParameters.singleOrNull()?.type?.isNullableAny() == true // signature matches
|
||||||
|
|
||||||
internal fun ResolvedCall<*>.firstArgumentAsExpressionOrNull(): KtExpression? =
|
internal fun ResolvedCall<*>.firstArgumentAsExpressionOrNull(): KtExpression? =
|
||||||
this.valueArgumentsByIndex?.firstOrNull()?.safeAs<ExpressionValueArgument>()?.valueArgument?.getArgumentExpression()
|
this.valueArgumentsByIndex?.firstOrNull()?.safeAs<ExpressionValueArgument>()?.valueArgument?.getArgumentExpression()
|
||||||
|
|
||||||
private fun DeclarationDescriptor.equalsDslDescriptor(dslName: Name): Boolean = this.name == dslName && this.isFromContractDsl()
|
private fun DeclarationDescriptor.equalsDslDescriptor(dslName: Name): Boolean = this.name == dslName && this.isFromContractDsl()
|
||||||
+2
-2
@@ -29,8 +29,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
|
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
|
||||||
|
|
||||||
internal class PsiCallsEffectParser(
|
internal class PsiCallsEffectParser(
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
contractParserDispatcher: PsiContractParserDispatcher
|
contractParserDispatcher: PsiContractParserDispatcher
|
||||||
) : AbstractPsiEffectParser(trace, contractParserDispatcher) {
|
) : AbstractPsiEffectParser(trace, contractParserDispatcher) {
|
||||||
|
|
||||||
override fun tryParseEffect(expression: KtExpression): EffectDeclaration? {
|
override fun tryParseEffect(expression: KtExpression): EffectDeclaration? {
|
||||||
|
|||||||
+4
-4
@@ -29,8 +29,8 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
internal class PsiConditionalEffectParser(
|
internal class PsiConditionalEffectParser(
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
dispatcher: PsiContractParserDispatcher
|
dispatcher: PsiContractParserDispatcher
|
||||||
) : AbstractPsiEffectParser(trace, dispatcher) {
|
) : AbstractPsiEffectParser(trace, dispatcher) {
|
||||||
override fun tryParseEffect(expression: KtExpression): EffectDeclaration? {
|
override fun tryParseEffect(expression: KtExpression): EffectDeclaration? {
|
||||||
val resolvedCall = expression.getResolvedCall(trace.bindingContext) ?: return null
|
val resolvedCall = expression.getResolvedCall(trace.bindingContext) ?: return null
|
||||||
@@ -38,9 +38,9 @@ internal class PsiConditionalEffectParser(
|
|||||||
if (!resolvedCall.resultingDescriptor.isImpliesCallDescriptor()) return null
|
if (!resolvedCall.resultingDescriptor.isImpliesCallDescriptor()) return null
|
||||||
|
|
||||||
val effect = contractParserDispatcher.parseEffect(resolvedCall.dispatchReceiver.safeAs<ExpressionReceiver>()?.expression)
|
val effect = contractParserDispatcher.parseEffect(resolvedCall.dispatchReceiver.safeAs<ExpressionReceiver>()?.expression)
|
||||||
?: return null
|
?: return null
|
||||||
val condition = contractParserDispatcher.parseCondition(resolvedCall.firstArgumentAsExpressionOrNull())
|
val condition = contractParserDispatcher.parseCondition(resolvedCall.firstArgumentAsExpressionOrNull())
|
||||||
?: return null
|
?: return null
|
||||||
|
|
||||||
return ConditionalEffectDeclaration(effect, condition)
|
return ConditionalEffectDeclaration(effect, condition)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-5
@@ -26,8 +26,8 @@ import org.jetbrains.kotlin.resolve.BindingTrace
|
|||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
|
||||||
internal class PsiReturnsEffectParser(
|
internal class PsiReturnsEffectParser(
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
contractParserDispatcher: PsiContractParserDispatcher
|
contractParserDispatcher: PsiContractParserDispatcher
|
||||||
) : AbstractPsiEffectParser(trace, contractParserDispatcher) {
|
) : AbstractPsiEffectParser(trace, contractParserDispatcher) {
|
||||||
override fun tryParseEffect(expression: KtExpression): EffectDeclaration? {
|
override fun tryParseEffect(expression: KtExpression): EffectDeclaration? {
|
||||||
val resolvedCall = expression.getResolvedCall(trace.bindingContext) ?: return null
|
val resolvedCall = expression.getResolvedCall(trace.bindingContext) ?: return null
|
||||||
@@ -39,13 +39,18 @@ internal class PsiReturnsEffectParser(
|
|||||||
if (!descriptor.isReturnsEffectDescriptor()) return null
|
if (!descriptor.isReturnsEffectDescriptor()) return null
|
||||||
|
|
||||||
val argumentExpression = resolvedCall.firstArgumentAsExpressionOrNull()
|
val argumentExpression = resolvedCall.firstArgumentAsExpressionOrNull()
|
||||||
val constantValue = if (argumentExpression == null)
|
val constantValue = if (argumentExpression == null) {
|
||||||
ConstantReference.WILDCARD
|
ConstantReference.WILDCARD
|
||||||
else {
|
} else {
|
||||||
// Note that we distinguish absence of an argument and unparsed argument
|
// Note that we distinguish absence of an argument and unparsed argument
|
||||||
val constant = contractParserDispatcher.parseConstant(argumentExpression)
|
val constant = contractParserDispatcher.parseConstant(argumentExpression)
|
||||||
if (constant == null) {
|
if (constant == null) {
|
||||||
trace.report(Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(argumentExpression, "only true/false/null constants in Returns-effect are currently supported"))
|
trace.report(
|
||||||
|
Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(
|
||||||
|
argumentExpression,
|
||||||
|
"only true/false/null constants in Returns-effect are currently supported"
|
||||||
|
)
|
||||||
|
)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
constant
|
constant
|
||||||
|
|||||||
+13
-10
@@ -40,22 +40,24 @@ import org.jetbrains.kotlin.storage.getValue
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class AnnotationSplitter(
|
class AnnotationSplitter(
|
||||||
val storageManager: StorageManager,
|
val storageManager: StorageManager,
|
||||||
allAnnotations: Annotations,
|
allAnnotations: Annotations,
|
||||||
applicableTargetsLazy: () -> Set<AnnotationUseSiteTarget>
|
applicableTargetsLazy: () -> Set<AnnotationUseSiteTarget>
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
private val TARGET_PRIORITIES = setOf(CONSTRUCTOR_PARAMETER, PROPERTY, FIELD)
|
private val TARGET_PRIORITIES = setOf(CONSTRUCTOR_PARAMETER, PROPERTY, FIELD)
|
||||||
|
|
||||||
@JvmStatic fun create(
|
@JvmStatic
|
||||||
storageManager: StorageManager,
|
fun create(
|
||||||
annotations: Annotations,
|
storageManager: StorageManager,
|
||||||
targets: Set<AnnotationUseSiteTarget>
|
annotations: Annotations,
|
||||||
|
targets: Set<AnnotationUseSiteTarget>
|
||||||
): AnnotationSplitter {
|
): AnnotationSplitter {
|
||||||
return AnnotationSplitter(storageManager, annotations, { targets })
|
return AnnotationSplitter(storageManager, annotations, { targets })
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun getTargetSet(parameter: Boolean, context: BindingContext, wrapper: PropertyWrapper): Set<AnnotationUseSiteTarget> {
|
@JvmStatic
|
||||||
|
fun getTargetSet(parameter: Boolean, context: BindingContext, wrapper: PropertyWrapper): Set<AnnotationUseSiteTarget> {
|
||||||
val descriptor = wrapper.descriptor
|
val descriptor = wrapper.descriptor
|
||||||
assert(descriptor != null)
|
assert(descriptor != null)
|
||||||
val hasBackingField = context[BindingContext.BACKING_FIELD_REQUIRED, descriptor] ?: false
|
val hasBackingField = context[BindingContext.BACKING_FIELD_REQUIRED, descriptor] ?: false
|
||||||
@@ -63,8 +65,9 @@ class AnnotationSplitter(
|
|||||||
return getTargetSet(parameter, descriptor!!.isVar, hasBackingField, hasDelegate)
|
return getTargetSet(parameter, descriptor!!.isVar, hasBackingField, hasDelegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun getTargetSet(
|
@JvmStatic
|
||||||
parameter: Boolean, isVar: Boolean, hasBackingField: Boolean, hasDelegate: Boolean
|
fun getTargetSet(
|
||||||
|
parameter: Boolean, isVar: Boolean, hasBackingField: Boolean, hasDelegate: Boolean
|
||||||
): Set<AnnotationUseSiteTarget> = hashSetOf(PROPERTY, PROPERTY_GETTER).apply {
|
): Set<AnnotationUseSiteTarget> = hashSetOf(PROPERTY, PROPERTY_GETTER).apply {
|
||||||
if (parameter) add(CONSTRUCTOR_PARAMETER)
|
if (parameter) add(CONSTRUCTOR_PARAMETER)
|
||||||
if (hasBackingField) add(FIELD)
|
if (hasBackingField) add(FIELD)
|
||||||
|
|||||||
+14
-12
@@ -23,31 +23,33 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
|||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
sealed class LocalVariableAccessorDescriptor(
|
sealed class LocalVariableAccessorDescriptor(
|
||||||
final override val correspondingVariable: LocalVariableDescriptor,
|
final override val correspondingVariable: LocalVariableDescriptor,
|
||||||
isGetter: Boolean
|
isGetter: Boolean
|
||||||
) : SimpleFunctionDescriptorImpl(
|
) : SimpleFunctionDescriptorImpl(
|
||||||
correspondingVariable.containingDeclaration,
|
correspondingVariable.containingDeclaration,
|
||||||
null,
|
null,
|
||||||
Annotations.EMPTY,
|
Annotations.EMPTY,
|
||||||
Name.special((if (isGetter) "<get-" else "<set-") + correspondingVariable.name + ">"),
|
Name.special((if (isGetter) "<get-" else "<set-") + correspondingVariable.name + ">"),
|
||||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||||
SourceElement.NO_SOURCE
|
SourceElement.NO_SOURCE
|
||||||
), VariableAccessorDescriptor {
|
), VariableAccessorDescriptor {
|
||||||
class Getter(correspondingVariable: LocalVariableDescriptor) : LocalVariableAccessorDescriptor(correspondingVariable, true)
|
class Getter(correspondingVariable: LocalVariableDescriptor) : LocalVariableAccessorDescriptor(correspondingVariable, true)
|
||||||
class Setter(correspondingVariable: LocalVariableDescriptor) : LocalVariableAccessorDescriptor(correspondingVariable, false)
|
class Setter(correspondingVariable: LocalVariableDescriptor) : LocalVariableAccessorDescriptor(correspondingVariable, false)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val valueParameters =
|
val valueParameters =
|
||||||
if (isGetter) emptyList() else listOf(createValueParameter(Name.identifier("value"), correspondingVariable.type))
|
if (isGetter) emptyList() else listOf(createValueParameter(Name.identifier("value"), correspondingVariable.type))
|
||||||
val returnType =
|
val returnType =
|
||||||
if (isGetter) correspondingVariable.type else correspondingVariable.builtIns.unitType
|
if (isGetter) correspondingVariable.type else correspondingVariable.builtIns.unitType
|
||||||
@Suppress("LeakingThis")
|
@Suppress("LeakingThis")
|
||||||
initialize(null, null, emptyList(), valueParameters, returnType, Modality.FINAL, Visibilities.LOCAL)
|
initialize(null, null, emptyList(), valueParameters, returnType, Modality.FINAL, Visibilities.LOCAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createValueParameter(name: Name, type: KotlinType): ValueParameterDescriptorImpl {
|
private fun createValueParameter(name: Name, type: KotlinType): ValueParameterDescriptorImpl {
|
||||||
return ValueParameterDescriptorImpl(this, null, 0, Annotations.EMPTY, name, type,
|
return ValueParameterDescriptorImpl(
|
||||||
false, false, false, null, SourceElement.NO_SOURCE)
|
this, null, 0, Annotations.EMPTY, name, type,
|
||||||
|
false, false, false, null, SourceElement.NO_SOURCE
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-7
@@ -25,15 +25,19 @@ import org.jetbrains.kotlin.psi.KtProperty
|
|||||||
import org.jetbrains.kotlin.resolve.source.toSourceElement
|
import org.jetbrains.kotlin.resolve.source.toSourceElement
|
||||||
|
|
||||||
class SyntheticFieldDescriptor private constructor(
|
class SyntheticFieldDescriptor private constructor(
|
||||||
val propertyDescriptor: PropertyDescriptor,
|
val propertyDescriptor: PropertyDescriptor,
|
||||||
|
accessorDescriptor: PropertyAccessorDescriptor,
|
||||||
|
property: KtProperty
|
||||||
|
) : LocalVariableDescriptor(
|
||||||
|
accessorDescriptor, Annotations.EMPTY, SyntheticFieldDescriptor.NAME,
|
||||||
|
propertyDescriptor.type, propertyDescriptor.isVar, false, false,
|
||||||
|
property.toSourceElement()
|
||||||
|
) {
|
||||||
|
|
||||||
|
constructor(
|
||||||
accessorDescriptor: PropertyAccessorDescriptor,
|
accessorDescriptor: PropertyAccessorDescriptor,
|
||||||
property: KtProperty
|
property: KtProperty
|
||||||
): LocalVariableDescriptor(accessorDescriptor, Annotations.EMPTY, SyntheticFieldDescriptor.NAME,
|
) : this(accessorDescriptor.correspondingProperty, accessorDescriptor, property)
|
||||||
propertyDescriptor.type, propertyDescriptor.isVar, false, false,
|
|
||||||
property.toSourceElement()) {
|
|
||||||
|
|
||||||
constructor(accessorDescriptor: PropertyAccessorDescriptor,
|
|
||||||
property: KtProperty): this(accessorDescriptor.correspondingProperty, accessorDescriptor, property)
|
|
||||||
|
|
||||||
override fun getDispatchReceiverParameter() = null
|
override fun getDispatchReceiverParameter() = null
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ package org.jetbrains.kotlin.diagnostics
|
|||||||
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticRenderer
|
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticRenderer
|
||||||
|
|
||||||
class RenderedDiagnostic<D : Diagnostic>(
|
class RenderedDiagnostic<D : Diagnostic>(
|
||||||
val diagnostic: D,
|
val diagnostic: D,
|
||||||
val renderer: DiagnosticRenderer<D>
|
val renderer: DiagnosticRenderer<D>
|
||||||
) {
|
) {
|
||||||
val text = renderer.render(diagnostic)
|
val text = renderer.render(diagnostic)
|
||||||
|
|
||||||
|
|||||||
@@ -44,42 +44,39 @@ import org.jetbrains.kotlin.types.typeUtil.isNothing
|
|||||||
import org.jetbrains.kotlin.types.typeUtil.isNullableNothing
|
import org.jetbrains.kotlin.types.typeUtil.isNullableNothing
|
||||||
|
|
||||||
fun ResolutionContext<*>.reportTypeMismatchDueToTypeProjection(
|
fun ResolutionContext<*>.reportTypeMismatchDueToTypeProjection(
|
||||||
expression: KtElement,
|
expression: KtElement,
|
||||||
expectedType: KotlinType,
|
expectedType: KotlinType,
|
||||||
expressionType: KotlinType?
|
expressionType: KotlinType?
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (!TypeUtils.contains(expectedType) { it.isAnyOrNullableAny() || it.isNothing() || it.isNullableNothing() }) return false
|
if (!TypeUtils.contains(expectedType) { it.isAnyOrNullableAny() || it.isNothing() || it.isNullableNothing() }) return false
|
||||||
|
|
||||||
val callPosition = this.callPosition
|
val callPosition = this.callPosition
|
||||||
val (resolvedCall, correspondingNotApproximatedTypeByDescriptor: (CallableDescriptor) -> KotlinType?) = when (callPosition) {
|
val (resolvedCall, correspondingNotApproximatedTypeByDescriptor: (CallableDescriptor) -> KotlinType?) = when (callPosition) {
|
||||||
is CallPosition.ValueArgumentPosition -> Pair(
|
is CallPosition.ValueArgumentPosition -> Pair(
|
||||||
callPosition.resolvedCall, {
|
callPosition.resolvedCall, { f: CallableDescriptor ->
|
||||||
f: CallableDescriptor ->
|
getEffectiveExpectedType(f.valueParameters[callPosition.valueParameter.index], callPosition.valueArgument, this)
|
||||||
getEffectiveExpectedType(f.valueParameters[callPosition.valueParameter.index], callPosition.valueArgument, this)
|
})
|
||||||
})
|
|
||||||
is CallPosition.ExtensionReceiverPosition -> Pair(
|
is CallPosition.ExtensionReceiverPosition -> Pair(
|
||||||
callPosition.resolvedCall, {
|
callPosition.resolvedCall, { f: CallableDescriptor ->
|
||||||
f: CallableDescriptor ->
|
f.extensionReceiverParameter?.type
|
||||||
f.extensionReceiverParameter?.type
|
})
|
||||||
})
|
|
||||||
is CallPosition.PropertyAssignment -> Pair(
|
is CallPosition.PropertyAssignment -> Pair(
|
||||||
callPosition.leftPart.getResolvedCall(trace.bindingContext) ?: return false, {
|
callPosition.leftPart.getResolvedCall(trace.bindingContext) ?: return false, { f: CallableDescriptor ->
|
||||||
f: CallableDescriptor ->
|
(f as? PropertyDescriptor)?.setter?.valueParameters?.get(0)?.type
|
||||||
(f as? PropertyDescriptor)?.setter?.valueParameters?.get(0)?.type
|
})
|
||||||
})
|
|
||||||
is CallPosition.Unknown -> return false
|
is CallPosition.Unknown -> return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val receiverType = resolvedCall.smartCastDispatchReceiverType
|
val receiverType = resolvedCall.smartCastDispatchReceiverType
|
||||||
?: (resolvedCall.dispatchReceiver ?: return false).type
|
?: (resolvedCall.dispatchReceiver ?: return false).type
|
||||||
|
|
||||||
val callableDescriptor = resolvedCall.resultingDescriptor.original
|
val callableDescriptor = resolvedCall.resultingDescriptor.original
|
||||||
|
|
||||||
val substitutedDescriptor =
|
val substitutedDescriptor =
|
||||||
TypeConstructorSubstitution
|
TypeConstructorSubstitution
|
||||||
.create(receiverType)
|
.create(receiverType)
|
||||||
.wrapWithCapturingSubstitution(needApproximation = false)
|
.wrapWithCapturingSubstitution(needApproximation = false)
|
||||||
.buildSubstitutor().let { callableDescriptor.substitute(it) } ?: return false
|
.buildSubstitutor().let { callableDescriptor.substitute(it) } ?: return false
|
||||||
|
|
||||||
val nonApproximatedExpectedType = correspondingNotApproximatedTypeByDescriptor(substitutedDescriptor) ?: return false
|
val nonApproximatedExpectedType = correspondingNotApproximatedTypeByDescriptor(substitutedDescriptor) ?: return false
|
||||||
if (!TypeUtils.contains(nonApproximatedExpectedType) { it.isCaptured() }) return false
|
if (!TypeUtils.contains(nonApproximatedExpectedType) { it.isCaptured() }) return false
|
||||||
@@ -87,25 +84,26 @@ fun ResolutionContext<*>.reportTypeMismatchDueToTypeProjection(
|
|||||||
if (expectedType.isNothing()) {
|
if (expectedType.isNothing()) {
|
||||||
if (callPosition is CallPosition.PropertyAssignment) {
|
if (callPosition is CallPosition.PropertyAssignment) {
|
||||||
trace.report(Errors.SETTER_PROJECTED_OUT.on(callPosition.leftPart ?: return false, resolvedCall.resultingDescriptor))
|
trace.report(Errors.SETTER_PROJECTED_OUT.on(callPosition.leftPart ?: return false, resolvedCall.resultingDescriptor))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val call = resolvedCall.call
|
val call = resolvedCall.call
|
||||||
val reportOn =
|
val reportOn =
|
||||||
if (resolvedCall is VariableAsFunctionResolvedCall)
|
if (resolvedCall is VariableAsFunctionResolvedCall)
|
||||||
resolvedCall.variableCall.call.calleeExpression
|
resolvedCall.variableCall.call.calleeExpression
|
||||||
else
|
else
|
||||||
call.calleeExpression
|
call.calleeExpression
|
||||||
|
|
||||||
trace.reportDiagnosticOnce(Errors.MEMBER_PROJECTED_OUT.on(reportOn ?: call.callElement, callableDescriptor, receiverType))
|
trace.reportDiagnosticOnce(Errors.MEMBER_PROJECTED_OUT.on(reportOn ?: call.callElement, callableDescriptor, receiverType))
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// expressionType can be null when reporting CONSTANT_EXPECTED_TYPE_MISMATCH (see addAll.kt test)
|
// expressionType can be null when reporting CONSTANT_EXPECTED_TYPE_MISMATCH (see addAll.kt test)
|
||||||
expressionType ?: return false
|
expressionType ?: return false
|
||||||
trace.report(
|
trace.report(
|
||||||
Errors.TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS.on(
|
Errors.TYPE_MISMATCH_DUE_TO_TYPE_PROJECTIONS.on(
|
||||||
expression, TypeMismatchDueToTypeProjectionsData(
|
expression, TypeMismatchDueToTypeProjectionsData(
|
||||||
expectedType, expressionType, receiverType, callableDescriptor)))
|
expectedType, expressionType, receiverType, callableDescriptor
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,16 +117,16 @@ fun BindingTrace.reportDiagnosticOnce(diagnostic: Diagnostic) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TypeMismatchDueToTypeProjectionsData(
|
class TypeMismatchDueToTypeProjectionsData(
|
||||||
val expectedType: KotlinType,
|
val expectedType: KotlinType,
|
||||||
val expressionType: KotlinType,
|
val expressionType: KotlinType,
|
||||||
val receiverType: KotlinType,
|
val receiverType: KotlinType,
|
||||||
val callableDescriptor: CallableDescriptor
|
val callableDescriptor: CallableDescriptor
|
||||||
)
|
)
|
||||||
|
|
||||||
fun ResolutionContext<*>.reportTypeMismatchDueToScalaLikeNamedFunctionSyntax(
|
fun ResolutionContext<*>.reportTypeMismatchDueToScalaLikeNamedFunctionSyntax(
|
||||||
expression: KtElement,
|
expression: KtElement,
|
||||||
expectedType: KotlinType,
|
expectedType: KotlinType,
|
||||||
expressionType: KotlinType?
|
expressionType: KotlinType?
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (expressionType == null) return false
|
if (expressionType == null) return false
|
||||||
|
|
||||||
@@ -141,21 +139,26 @@ fun ResolutionContext<*>.reportTypeMismatchDueToScalaLikeNamedFunctionSyntax(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isScalaLikeEqualsBlock(expression: KtElement): Boolean =
|
private fun isScalaLikeEqualsBlock(expression: KtElement): Boolean =
|
||||||
expression is KtLambdaExpression &&
|
expression is KtLambdaExpression &&
|
||||||
expression.parent.let { it is KtNamedFunction && it.equalsToken != null }
|
expression.parent.let { it is KtNamedFunction && it.equalsToken != null }
|
||||||
|
|
||||||
inline fun reportOnDeclaration(trace: BindingTrace, descriptor: DeclarationDescriptor, what: (PsiElement) -> Diagnostic) {
|
inline fun reportOnDeclaration(trace: BindingTrace, descriptor: DeclarationDescriptor, what: (PsiElement) -> Diagnostic) {
|
||||||
DescriptorToSourceUtils.descriptorToDeclaration(descriptor)?.let { psiElement ->
|
DescriptorToSourceUtils.descriptorToDeclaration(descriptor)?.let { psiElement ->
|
||||||
trace.report(what(psiElement))
|
trace.report(what(psiElement))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun reportOnDeclarationOrFail(trace: BindingTrace, descriptor: DeclarationDescriptor, what: (PsiElement) -> Diagnostic) {
|
inline fun reportOnDeclarationOrFail(trace: BindingTrace, descriptor: DeclarationDescriptor, what: (PsiElement) -> Diagnostic) {
|
||||||
DescriptorToSourceUtils.descriptorToDeclaration(descriptor)?.let { psiElement ->
|
DescriptorToSourceUtils.descriptorToDeclaration(descriptor)?.let { psiElement ->
|
||||||
trace.report(what(psiElement))
|
trace.report(what(psiElement))
|
||||||
} ?: throw AssertionError("No declaration for $descriptor")
|
} ?: throw AssertionError("No declaration for $descriptor")
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : KtDeclaration> reportOnDeclarationAs(trace: BindingTrace, descriptor: DeclarationDescriptor, what: (T) -> Diagnostic) {
|
inline fun <reified T : KtDeclaration> reportOnDeclarationAs(
|
||||||
|
trace: BindingTrace,
|
||||||
|
descriptor: DeclarationDescriptor,
|
||||||
|
what: (T) -> Diagnostic
|
||||||
|
) {
|
||||||
DescriptorToSourceUtils.descriptorToDeclaration(descriptor)?.let { psiElement ->
|
DescriptorToSourceUtils.descriptorToDeclaration(descriptor)?.let { psiElement ->
|
||||||
(psiElement as? T)?.let {
|
(psiElement as? T)?.let {
|
||||||
trace.report(what(it))
|
trace.report(what(it))
|
||||||
@@ -166,7 +169,7 @@ inline fun <reified T : KtDeclaration> reportOnDeclarationAs(trace: BindingTrace
|
|||||||
fun <D : Diagnostic> DiagnosticSink.reportFromPlugin(diagnostic: D, ext: DefaultErrorMessages.Extension) {
|
fun <D : Diagnostic> DiagnosticSink.reportFromPlugin(diagnostic: D, ext: DefaultErrorMessages.Extension) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val renderer = ext.map[diagnostic.factory] as? DiagnosticRenderer<D>
|
val renderer = ext.map[diagnostic.factory] as? DiagnosticRenderer<D>
|
||||||
?: error("Renderer not found for diagnostic ${diagnostic.factory.name}")
|
?: error("Renderer not found for diagnostic ${diagnostic.factory.name}")
|
||||||
|
|
||||||
val renderedDiagnostic = RenderedDiagnostic(diagnostic, renderer)
|
val renderedDiagnostic = RenderedDiagnostic(diagnostic, renderer)
|
||||||
|
|
||||||
|
|||||||
+4
-5
@@ -20,9 +20,9 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
|||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
|
|
||||||
class LanguageFeatureMessageRenderer @JvmOverloads constructor(
|
class LanguageFeatureMessageRenderer @JvmOverloads constructor(
|
||||||
private val type: Type,
|
private val type: Type,
|
||||||
private val useHtml: Boolean = false
|
private val useHtml: Boolean = false
|
||||||
): DiagnosticParameterRenderer<Pair<LanguageFeature, LanguageVersionSettings>> {
|
) : DiagnosticParameterRenderer<Pair<LanguageFeature, LanguageVersionSettings>> {
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
UNSUPPORTED,
|
UNSUPPORTED,
|
||||||
@@ -58,8 +58,7 @@ class LanguageFeatureMessageRenderer @JvmOverloads constructor(
|
|||||||
if (hintUrl != null) {
|
if (hintUrl != null) {
|
||||||
if (useHtml) {
|
if (useHtml) {
|
||||||
sb.append(" (").append("see more <a href=\"").append(hintUrl).append("\">here</a>)")
|
sb.append(" (").append("see more <a href=\"").append(hintUrl).append("\">here</a>)")
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
sb.append(" (see: ").append(hintUrl).append(")")
|
sb.append(" (see: ").append(hintUrl).append(")")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-14
@@ -21,11 +21,11 @@ import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
|||||||
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker.Compatibility.Incompatible
|
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker.Compatibility.Incompatible
|
||||||
|
|
||||||
class PlatformIncompatibilityDiagnosticRenderer(
|
class PlatformIncompatibilityDiagnosticRenderer(
|
||||||
private val mode: MultiplatformDiagnosticRenderingMode
|
private val mode: MultiplatformDiagnosticRenderingMode
|
||||||
) : DiagnosticParameterRenderer<Map<Incompatible, Collection<MemberDescriptor>>> {
|
) : DiagnosticParameterRenderer<Map<Incompatible, Collection<MemberDescriptor>>> {
|
||||||
override fun render(
|
override fun render(
|
||||||
obj: Map<Incompatible, Collection<MemberDescriptor>>,
|
obj: Map<Incompatible, Collection<MemberDescriptor>>,
|
||||||
renderingContext: RenderingContext
|
renderingContext: RenderingContext
|
||||||
): String {
|
): String {
|
||||||
if (obj.isEmpty()) return ""
|
if (obj.isEmpty()) return ""
|
||||||
|
|
||||||
@@ -42,11 +42,11 @@ class PlatformIncompatibilityDiagnosticRenderer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class IncompatibleExpectedActualClassScopesRenderer(
|
class IncompatibleExpectedActualClassScopesRenderer(
|
||||||
private val mode: MultiplatformDiagnosticRenderingMode
|
private val mode: MultiplatformDiagnosticRenderingMode
|
||||||
) : DiagnosticParameterRenderer<List<Pair<MemberDescriptor, Map<Incompatible, Collection<MemberDescriptor>>>>> {
|
) : DiagnosticParameterRenderer<List<Pair<MemberDescriptor, Map<Incompatible, Collection<MemberDescriptor>>>>> {
|
||||||
override fun render(
|
override fun render(
|
||||||
obj: List<Pair<MemberDescriptor, Map<Incompatible, Collection<MemberDescriptor>>>>,
|
obj: List<Pair<MemberDescriptor, Map<Incompatible, Collection<MemberDescriptor>>>>,
|
||||||
renderingContext: RenderingContext
|
renderingContext: RenderingContext
|
||||||
): String {
|
): String {
|
||||||
if (obj.isEmpty()) return ""
|
if (obj.isEmpty()) return ""
|
||||||
|
|
||||||
@@ -82,10 +82,10 @@ open class MultiplatformDiagnosticRenderingMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun StringBuilder.renderIncompatibilityInformation(
|
private fun StringBuilder.renderIncompatibilityInformation(
|
||||||
map: Map<Incompatible, Collection<MemberDescriptor>>,
|
map: Map<Incompatible, Collection<MemberDescriptor>>,
|
||||||
indent: String,
|
indent: String,
|
||||||
context: RenderingContext,
|
context: RenderingContext,
|
||||||
mode: MultiplatformDiagnosticRenderingMode
|
mode: MultiplatformDiagnosticRenderingMode
|
||||||
) {
|
) {
|
||||||
for ((incompatibility, descriptors) in map) {
|
for ((incompatibility, descriptors) in map) {
|
||||||
append(indent)
|
append(indent)
|
||||||
@@ -109,10 +109,10 @@ private fun StringBuilder.renderIncompatibilityInformation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun StringBuilder.renderIncompatibleClassScopes(
|
private fun StringBuilder.renderIncompatibleClassScopes(
|
||||||
unfulfilled: List<Pair<MemberDescriptor, Map<Incompatible, Collection<MemberDescriptor>>>>,
|
unfulfilled: List<Pair<MemberDescriptor, Map<Incompatible, Collection<MemberDescriptor>>>>,
|
||||||
indent: String,
|
indent: String,
|
||||||
context: RenderingContext,
|
context: RenderingContext,
|
||||||
mode: MultiplatformDiagnosticRenderingMode
|
mode: MultiplatformDiagnosticRenderingMode
|
||||||
) {
|
) {
|
||||||
mode.renderList(this, unfulfilled.indices.map { index ->
|
mode.renderList(this, unfulfilled.indices.map { index ->
|
||||||
{
|
{
|
||||||
|
|||||||
+16
-16
@@ -33,8 +33,8 @@ abstract class AbstractDiagnosticWithParametersRenderer<D : Diagnostic> protecte
|
|||||||
|
|
||||||
|
|
||||||
class DiagnosticWithParameters1Renderer<A : Any>(
|
class DiagnosticWithParameters1Renderer<A : Any>(
|
||||||
message: String,
|
message: String,
|
||||||
private val rendererForA: DiagnosticParameterRenderer<A>?
|
private val rendererForA: DiagnosticParameterRenderer<A>?
|
||||||
) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters1<*, A>>(message) {
|
) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters1<*, A>>(message) {
|
||||||
|
|
||||||
override fun renderParameters(diagnostic: DiagnosticWithParameters1<*, A>): Array<out Any> {
|
override fun renderParameters(diagnostic: DiagnosticWithParameters1<*, A>): Array<out Any> {
|
||||||
@@ -44,40 +44,40 @@ class DiagnosticWithParameters1Renderer<A : Any>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DiagnosticWithParameters2Renderer<A : Any, B : Any>(
|
class DiagnosticWithParameters2Renderer<A : Any, B : Any>(
|
||||||
message: String,
|
message: String,
|
||||||
private val rendererForA: DiagnosticParameterRenderer<A>?,
|
private val rendererForA: DiagnosticParameterRenderer<A>?,
|
||||||
private val rendererForB: DiagnosticParameterRenderer<B>?
|
private val rendererForB: DiagnosticParameterRenderer<B>?
|
||||||
) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters2<*, A, B>>(message) {
|
) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters2<*, A, B>>(message) {
|
||||||
|
|
||||||
override fun renderParameters(diagnostic: DiagnosticWithParameters2<*, A, B>): Array<out Any> {
|
override fun renderParameters(diagnostic: DiagnosticWithParameters2<*, A, B>): Array<out Any> {
|
||||||
val context = RenderingContext.of(diagnostic.a, diagnostic.b)
|
val context = RenderingContext.of(diagnostic.a, diagnostic.b)
|
||||||
return arrayOf(
|
return arrayOf(
|
||||||
renderParameter(diagnostic.a, rendererForA, context),
|
renderParameter(diagnostic.a, rendererForA, context),
|
||||||
renderParameter(diagnostic.b, rendererForB, context)
|
renderParameter(diagnostic.b, rendererForB, context)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DiagnosticWithParameters3Renderer<A : Any, B : Any, C : Any>(
|
class DiagnosticWithParameters3Renderer<A : Any, B : Any, C : Any>(
|
||||||
message: String,
|
message: String,
|
||||||
private val rendererForA: DiagnosticParameterRenderer<A>?,
|
private val rendererForA: DiagnosticParameterRenderer<A>?,
|
||||||
private val rendererForB: DiagnosticParameterRenderer<B>?,
|
private val rendererForB: DiagnosticParameterRenderer<B>?,
|
||||||
private val rendererForC: DiagnosticParameterRenderer<C>?
|
private val rendererForC: DiagnosticParameterRenderer<C>?
|
||||||
) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters3<*, A, B, C>>(message) {
|
) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters3<*, A, B, C>>(message) {
|
||||||
|
|
||||||
override fun renderParameters(diagnostic: DiagnosticWithParameters3<*, A, B, C>): Array<out Any> {
|
override fun renderParameters(diagnostic: DiagnosticWithParameters3<*, A, B, C>): Array<out Any> {
|
||||||
val context = RenderingContext.of(diagnostic.a, diagnostic.b, diagnostic.c)
|
val context = RenderingContext.of(diagnostic.a, diagnostic.b, diagnostic.c)
|
||||||
return arrayOf(
|
return arrayOf(
|
||||||
renderParameter(diagnostic.a, rendererForA, context),
|
renderParameter(diagnostic.a, rendererForA, context),
|
||||||
renderParameter(diagnostic.b, rendererForB, context),
|
renderParameter(diagnostic.b, rendererForB, context),
|
||||||
renderParameter(diagnostic.c, rendererForC, context)
|
renderParameter(diagnostic.c, rendererForC, context)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DiagnosticWithParametersMultiRenderer<A>(
|
class DiagnosticWithParametersMultiRenderer<A>(
|
||||||
message: String,
|
message: String,
|
||||||
private val renderer: MultiRenderer<A>
|
private val renderer: MultiRenderer<A>
|
||||||
) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters1<*, A>>(message) {
|
) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters1<*, A>>(message) {
|
||||||
|
|
||||||
override fun renderParameters(diagnostic: DiagnosticWithParameters1<*, A>): Array<out Any> {
|
override fun renderParameters(diagnostic: DiagnosticWithParameters1<*, A>): Array<out Any> {
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ interface AnnotationBasedExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun AnnotationDescriptor.isASpecialAnnotation(
|
private fun AnnotationDescriptor.isASpecialAnnotation(
|
||||||
specialAnnotations: List<String>,
|
specialAnnotations: List<String>,
|
||||||
visitedAnnotations: MutableSet<String> = hashSetOf(),
|
visitedAnnotations: MutableSet<String> = hashSetOf(),
|
||||||
allowMetaAnnotations: Boolean = true
|
allowMetaAnnotations: Boolean = true
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val annotationFqName = fqName?.asString() ?: return false
|
val annotationFqName = fqName?.asString() ?: return false
|
||||||
if (annotationFqName in visitedAnnotations) return false // Prevent infinite recursion
|
if (annotationFqName in visitedAnnotations) return false // Prevent infinite recursion
|
||||||
|
|||||||
+9
-9
@@ -24,21 +24,21 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
|||||||
|
|
||||||
interface DeclarationAttributeAltererExtension {
|
interface DeclarationAttributeAltererExtension {
|
||||||
companion object : ProjectExtensionDescriptor<DeclarationAttributeAltererExtension>(
|
companion object : ProjectExtensionDescriptor<DeclarationAttributeAltererExtension>(
|
||||||
"org.jetbrains.kotlin.declarationAttributeAltererExtension",
|
"org.jetbrains.kotlin.declarationAttributeAltererExtension",
|
||||||
DeclarationAttributeAltererExtension::class.java
|
DeclarationAttributeAltererExtension::class.java
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the new modality for the [declaration], or null if the [currentModality] is good enough.
|
* Returns the new modality for the [declaration], or null if the [currentModality] is good enough.
|
||||||
*/
|
*/
|
||||||
fun refineDeclarationModality(
|
fun refineDeclarationModality(
|
||||||
modifierListOwner: KtModifierListOwner,
|
modifierListOwner: KtModifierListOwner,
|
||||||
declaration: DeclarationDescriptor?,
|
declaration: DeclarationDescriptor?,
|
||||||
containingDeclaration: DeclarationDescriptor?,
|
containingDeclaration: DeclarationDescriptor?,
|
||||||
currentModality: Modality,
|
currentModality: Modality,
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
isImplicitModality: Boolean
|
isImplicitModality: Boolean
|
||||||
): Modality? = null
|
): Modality? = null
|
||||||
|
|
||||||
fun shouldConvertFirstSAMParameterToReceiver(function: FunctionDescriptor) : Boolean = false
|
fun shouldConvertFirstSAMParameterToReceiver(function: FunctionDescriptor): Boolean = false
|
||||||
}
|
}
|
||||||
+5
-3
@@ -27,9 +27,10 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
|||||||
*/
|
*/
|
||||||
interface PreprocessedVirtualFileFactoryExtension {
|
interface PreprocessedVirtualFileFactoryExtension {
|
||||||
companion object : ProjectExtensionDescriptor<PreprocessedVirtualFileFactoryExtension>(
|
companion object : ProjectExtensionDescriptor<PreprocessedVirtualFileFactoryExtension>(
|
||||||
"org.jetbrains.kotlin.preprocessedVirtualFileFactoryExtension",
|
"org.jetbrains.kotlin.preprocessedVirtualFileFactoryExtension",
|
||||||
PreprocessedVirtualFileFactoryExtension::class.java
|
PreprocessedVirtualFileFactoryExtension::class.java
|
||||||
)
|
)
|
||||||
|
|
||||||
fun isPassThrough(): Boolean
|
fun isPassThrough(): Boolean
|
||||||
|
|
||||||
fun createPreprocessedFile(file: VirtualFile?): VirtualFile?
|
fun createPreprocessedFile(file: VirtualFile?): VirtualFile?
|
||||||
@@ -45,6 +46,7 @@ class PreprocessedFileCreator(val project: Project) {
|
|||||||
fun create(file: VirtualFile): VirtualFile = validExts.firstNotNullResult { it.createPreprocessedFile(file) } ?: file
|
fun create(file: VirtualFile): VirtualFile = validExts.firstNotNullResult { it.createPreprocessedFile(file) } ?: file
|
||||||
|
|
||||||
// unused now, but could be used in the IDE at some point
|
// unused now, but could be used in the IDE at some point
|
||||||
fun createLight(file: LightVirtualFile): LightVirtualFile = validExts.firstNotNullResult { it.createPreprocessedLightFile(file) } ?: file
|
fun createLight(file: LightVirtualFile): LightVirtualFile =
|
||||||
|
validExts.firstNotNullResult { it.createPreprocessedLightFile(file) } ?: file
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ open class ProjectExtensionDescriptor<T>(name: String, private val extensionClas
|
|||||||
|
|
||||||
fun registerExtensionPoint(project: Project) {
|
fun registerExtensionPoint(project: Project) {
|
||||||
Extensions.getArea(project).registerExtensionPoint(
|
Extensions.getArea(project).registerExtensionPoint(
|
||||||
extensionPointName.name,
|
extensionPointName.name,
|
||||||
extensionClass.name,
|
extensionClass.name,
|
||||||
ExtensionPoint.Kind.INTERFACE
|
ExtensionPoint.Kind.INTERFACE
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.resolve.TargetPlatform
|
|||||||
|
|
||||||
interface StorageComponentContainerContributor {
|
interface StorageComponentContainerContributor {
|
||||||
companion object : ProjectExtensionDescriptor<StorageComponentContainerContributor>(
|
companion object : ProjectExtensionDescriptor<StorageComponentContainerContributor>(
|
||||||
"org.jetbrains.kotlin.storageComponentContainerContributor", StorageComponentContainerContributor::class.java
|
"org.jetbrains.kotlin.storageComponentContainerContributor", StorageComponentContainerContributor::class.java
|
||||||
)
|
)
|
||||||
|
|
||||||
fun registerModuleComponents(container: StorageComponentContainer, platform: TargetPlatform, moduleDescriptor: ModuleDescriptor) {}
|
fun registerModuleComponents(container: StorageComponentContainer, platform: TargetPlatform, moduleDescriptor: ModuleDescriptor) {}
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ enum class KDocKnownTag private constructor(val isReferenceRequired: Boolean, va
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return valueOf(tagName.toString().toUpperCase())
|
return valueOf(tagName.toString().toUpperCase())
|
||||||
}
|
} catch (ignored: IllegalArgumentException) {
|
||||||
catch (ignored: IllegalArgumentException) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getChildOfType
|
|||||||
/**
|
/**
|
||||||
* A single part of a qualified name in the tag subject or link.
|
* A single part of a qualified name in the tag subject or link.
|
||||||
*/
|
*/
|
||||||
class KDocName(node: ASTNode): KtElementImpl(node) {
|
class KDocName(node: ASTNode) : KtElementImpl(node) {
|
||||||
fun getContainingDoc(): KDoc {
|
fun getContainingDoc(): KDoc {
|
||||||
val kdoc = getStrictParentOfType<KDoc>()
|
val kdoc = getStrictParentOfType<KDoc>()
|
||||||
return kdoc ?: throw IllegalStateException("KDocName must be inside a KDoc")
|
return kdoc ?: throw IllegalStateException("KDocName must be inside a KDoc")
|
||||||
|
|||||||
@@ -292,9 +292,11 @@ private object DebugTextBuildingVisitor : KtVisitor<String, Unit>() {
|
|||||||
private fun StringBuilder.appendInn(target: Any?, prefix: String = "", suffix: String = "") {
|
private fun StringBuilder.appendInn(target: Any?, prefix: String = "", suffix: String = "") {
|
||||||
if (target == null) return
|
if (target == null) return
|
||||||
append(prefix)
|
append(prefix)
|
||||||
append(when (target) {
|
append(
|
||||||
is KtElement -> target.getDebugText()
|
when (target) {
|
||||||
else -> target.toString()
|
is KtElement -> target.getDebugText()
|
||||||
})
|
else -> target.toString()
|
||||||
|
}
|
||||||
|
)
|
||||||
append(suffix)
|
append(suffix)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,28 +24,31 @@ import org.jetbrains.kotlin.psi.psiUtil.siblings
|
|||||||
|
|
||||||
object EditCommaSeparatedListHelper {
|
object EditCommaSeparatedListHelper {
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun <TItem: KtElement> addItem(list: KtElement, allItems: List<TItem>, item: TItem, prefix: KtToken = KtTokens.LPAR): TItem {
|
fun <TItem : KtElement> addItem(list: KtElement, allItems: List<TItem>, item: TItem, prefix: KtToken = KtTokens.LPAR): TItem {
|
||||||
return addItemBefore(list, allItems, item, null, prefix)
|
return addItemBefore(list, allItems, item, null, prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun <TItem: KtElement> addItemAfter(list: KtElement, allItems: List<TItem>, item: TItem, anchor: TItem?, prefix: KtToken = KtTokens.LPAR): TItem {
|
fun <TItem : KtElement> addItemAfter(
|
||||||
|
list: KtElement,
|
||||||
|
allItems: List<TItem>,
|
||||||
|
item: TItem,
|
||||||
|
anchor: TItem?,
|
||||||
|
prefix: KtToken = KtTokens.LPAR
|
||||||
|
): TItem {
|
||||||
assert(anchor == null || anchor.parent == list)
|
assert(anchor == null || anchor.parent == list)
|
||||||
if (allItems.isEmpty()) {
|
if (allItems.isEmpty()) {
|
||||||
return if (list.firstChild?.node?.elementType == prefix) {
|
return if (list.firstChild?.node?.elementType == prefix) {
|
||||||
list.addAfter(item, list.firstChild) as TItem
|
list.addAfter(item, list.firstChild) as TItem
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
list.add(item) as TItem
|
list.add(item) as TItem
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
var comma = KtPsiFactory(list).createComma()
|
var comma = KtPsiFactory(list).createComma()
|
||||||
return if (anchor != null) {
|
return if (anchor != null) {
|
||||||
comma = list.addAfter(comma, anchor)
|
comma = list.addAfter(comma, anchor)
|
||||||
list.addAfter(item, comma) as TItem
|
list.addAfter(item, comma) as TItem
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
comma = list.addBefore(comma, allItems.first())
|
comma = list.addBefore(comma, allItems.first())
|
||||||
list.addBefore(item, comma) as TItem
|
list.addBefore(item, comma) as TItem
|
||||||
}
|
}
|
||||||
@@ -53,26 +56,30 @@ object EditCommaSeparatedListHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun <TItem: KtElement> addItemBefore(list: KtElement, allItems: List<TItem>, item: TItem, anchor: TItem?, prefix: KtToken = KtTokens.LPAR): TItem {
|
fun <TItem : KtElement> addItemBefore(
|
||||||
|
list: KtElement,
|
||||||
|
allItems: List<TItem>,
|
||||||
|
item: TItem,
|
||||||
|
anchor: TItem?,
|
||||||
|
prefix: KtToken = KtTokens.LPAR
|
||||||
|
): TItem {
|
||||||
val anchorAfter: TItem?
|
val anchorAfter: TItem?
|
||||||
anchorAfter = if (allItems.isEmpty()) {
|
anchorAfter = if (allItems.isEmpty()) {
|
||||||
assert(anchor == null)
|
assert(anchor == null)
|
||||||
null
|
null
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (anchor != null) {
|
if (anchor != null) {
|
||||||
val index = allItems.indexOf(anchor)
|
val index = allItems.indexOf(anchor)
|
||||||
assert(index >= 0)
|
assert(index >= 0)
|
||||||
if (index > 0) allItems[index - 1] else null
|
if (index > 0) allItems[index - 1] else null
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
allItems[allItems.size - 1]
|
allItems[allItems.size - 1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return addItemAfter(list, allItems, item, anchorAfter, prefix)
|
return addItemAfter(list, allItems, item, anchorAfter, prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <TItem: KtElement> removeItem(item: TItem) {
|
fun <TItem : KtElement> removeItem(item: TItem) {
|
||||||
var comma = item.siblings(withItself = false).firstOrNull { it !is PsiWhiteSpace && it !is PsiComment }
|
var comma = item.siblings(withItself = false).firstOrNull { it !is PsiWhiteSpace && it !is PsiComment }
|
||||||
if (comma?.node?.elementType != KtTokens.COMMA) {
|
if (comma?.node?.elementType != KtTokens.COMMA) {
|
||||||
comma = item.siblings(forward = false, withItself = false).firstOrNull { it !is PsiWhiteSpace && it !is PsiComment }
|
comma = item.siblings(forward = false, withItself = false).firstOrNull { it !is PsiWhiteSpace && it !is PsiComment }
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ import org.jetbrains.kotlin.psi.psiUtil.allChildren
|
|||||||
|
|
||||||
fun findDocComment(declaration: KtDeclaration): KDoc? {
|
fun findDocComment(declaration: KtDeclaration): KDoc? {
|
||||||
return declaration.allChildren
|
return declaration.allChildren
|
||||||
.flatMap {
|
.flatMap {
|
||||||
if (it is KtDeclarationModifierList) {
|
if (it is KtDeclarationModifierList) {
|
||||||
return@flatMap it.children.asSequence()
|
return@flatMap it.children.asSequence()
|
||||||
}
|
|
||||||
sequenceOf(it)
|
|
||||||
}
|
}
|
||||||
.dropWhile { it !is KDoc }
|
sequenceOf(it)
|
||||||
.firstOrNull() as? KDoc
|
}
|
||||||
|
.dropWhile { it !is KDoc }
|
||||||
|
.firstOrNull() as? KDoc
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ import com.intellij.psi.PsiElement
|
|||||||
import org.jetbrains.kotlin.KtNodeTypes
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
|
|
||||||
class KtBlockCodeFragment(
|
class KtBlockCodeFragment(
|
||||||
project: Project,
|
project: Project,
|
||||||
name: String,
|
name: String,
|
||||||
text: CharSequence,
|
text: CharSequence,
|
||||||
imports: String?,
|
imports: String?,
|
||||||
context: PsiElement?
|
context: PsiElement?
|
||||||
) : KtCodeFragment(project, name, text, imports, KtNodeTypes.BLOCK_CODE_FRAGMENT, context) {
|
) : KtCodeFragment(project, name, text, imports, KtNodeTypes.BLOCK_CODE_FRAGMENT, context) {
|
||||||
|
|
||||||
override fun getContentElement() = findChildByClass(KtBlockExpression::class.java)
|
override fun getContentElement() = findChildByClass(KtBlockExpression::class.java)
|
||||||
?: throw IllegalStateException("Block expression should be parsed for BlockCodeFragment")
|
?: throw IllegalStateException("Block expression should be parsed for BlockCodeFragment")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ import org.jetbrains.kotlin.psi.stubs.KotlinClassOrObjectStub
|
|||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||||
|
|
||||||
abstract class KtClassOrObject :
|
abstract class KtClassOrObject :
|
||||||
KtTypeParameterListOwnerStub<KotlinClassOrObjectStub<out KtClassOrObject>>, KtDeclarationContainer, KtNamedDeclaration, KtPureClassOrObject {
|
KtTypeParameterListOwnerStub<KotlinClassOrObjectStub<out KtClassOrObject>>, KtDeclarationContainer, KtNamedDeclaration,
|
||||||
|
KtPureClassOrObject {
|
||||||
constructor(node: ASTNode) : super(node)
|
constructor(node: ASTNode) : super(node)
|
||||||
constructor(stub: KotlinClassOrObjectStub<out KtClassOrObject>, nodeType: IStubElementType<*, *>) : super(stub, nodeType)
|
constructor(stub: KotlinClassOrObjectStub<out KtClassOrObject>, nodeType: IStubElementType<*, *>) : super(stub, nodeType)
|
||||||
|
|
||||||
@@ -59,8 +60,7 @@ abstract class KtClassOrObject :
|
|||||||
|
|
||||||
if (specifierList.entries.size > 1) {
|
if (specifierList.entries.size > 1) {
|
||||||
EditCommaSeparatedListHelper.removeItem<KtElement>(superTypeListEntry)
|
EditCommaSeparatedListHelper.removeItem<KtElement>(superTypeListEntry)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
deleteChildRange(findChildByType<PsiElement>(KtTokens.COLON) ?: specifierList, specifierList)
|
deleteChildRange(findChildByType<PsiElement>(KtTokens.COLON) ?: specifierList, specifierList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,18 +69,18 @@ abstract class KtClassOrObject :
|
|||||||
|
|
||||||
fun getBody(): KtClassBody? = getStubOrPsiChild(KtStubElementTypes.CLASS_BODY)
|
fun getBody(): KtClassBody? = getStubOrPsiChild(KtStubElementTypes.CLASS_BODY)
|
||||||
|
|
||||||
inline fun <reified T: KtDeclaration> addDeclaration(declaration: T): T {
|
inline fun <reified T : KtDeclaration> addDeclaration(declaration: T): T {
|
||||||
val body = getOrCreateBody()
|
val body = getOrCreateBody()
|
||||||
val anchor = PsiTreeUtil.skipSiblingsBackward(body.rBrace ?: body.lastChild!!, PsiWhiteSpace::class.java)
|
val anchor = PsiTreeUtil.skipSiblingsBackward(body.rBrace ?: body.lastChild!!, PsiWhiteSpace::class.java)
|
||||||
return body.addAfter(declaration, anchor) as T
|
return body.addAfter(declaration, anchor) as T
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T: KtDeclaration> addDeclarationAfter(declaration: T, anchor: PsiElement?): T {
|
inline fun <reified T : KtDeclaration> addDeclarationAfter(declaration: T, anchor: PsiElement?): T {
|
||||||
val anchorBefore = anchor ?: declarations.lastOrNull() ?: return addDeclaration(declaration)
|
val anchorBefore = anchor ?: declarations.lastOrNull() ?: return addDeclaration(declaration)
|
||||||
return getOrCreateBody().addAfter(declaration, anchorBefore) as T
|
return getOrCreateBody().addAfter(declaration, anchorBefore) as T
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T: KtDeclaration> addDeclarationBefore(declaration: T, anchor: PsiElement?): T {
|
inline fun <reified T : KtDeclaration> addDeclarationBefore(declaration: T, anchor: PsiElement?): T {
|
||||||
val anchorAfter = anchor ?: declarations.firstOrNull() ?: return addDeclaration(declaration)
|
val anchorAfter = anchor ?: declarations.firstOrNull() ?: return addDeclaration(declaration)
|
||||||
return getOrCreateBody().addBefore(declaration, anchorAfter) as T
|
return getOrCreateBody().addBefore(declaration, anchorAfter) as T
|
||||||
}
|
}
|
||||||
@@ -112,9 +112,11 @@ abstract class KtClassOrObject :
|
|||||||
fun isAnnotation(): Boolean = hasModifier(KtTokens.ANNOTATION_KEYWORD)
|
fun isAnnotation(): Boolean = hasModifier(KtTokens.ANNOTATION_KEYWORD)
|
||||||
|
|
||||||
fun getDeclarationKeyword(): PsiElement? =
|
fun getDeclarationKeyword(): PsiElement? =
|
||||||
findChildByType(TokenSet.create(
|
findChildByType(
|
||||||
KtTokens.CLASS_KEYWORD, KtTokens.INTERFACE_KEYWORD, KtTokens.OBJECT_KEYWORD
|
TokenSet.create(
|
||||||
))
|
KtTokens.CLASS_KEYWORD, KtTokens.INTERFACE_KEYWORD, KtTokens.OBJECT_KEYWORD
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
override fun delete() {
|
override fun delete() {
|
||||||
CheckUtil.checkWritable(this)
|
CheckUtil.checkWritable(this)
|
||||||
@@ -122,8 +124,7 @@ abstract class KtClassOrObject :
|
|||||||
val file = containingKtFile
|
val file = containingKtFile
|
||||||
if (!isTopLevel() || file.declarations.size > 1) {
|
if (!isTopLevel() || file.declarations.size > 1) {
|
||||||
super.delete()
|
super.delete()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
file.delete()
|
file.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,13 +31,21 @@ import org.jetbrains.kotlin.types.KotlinType
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
abstract class KtCodeFragment(
|
abstract class KtCodeFragment(
|
||||||
private val _project: Project,
|
private val _project: Project,
|
||||||
name: String,
|
name: String,
|
||||||
text: CharSequence,
|
text: CharSequence,
|
||||||
imports: String?, // Should be separated by JetCodeFragment.IMPORT_SEPARATOR
|
imports: String?, // Should be separated by JetCodeFragment.IMPORT_SEPARATOR
|
||||||
elementType: IElementType,
|
elementType: IElementType,
|
||||||
private val context: PsiElement?
|
private val context: PsiElement?
|
||||||
): KtFile((PsiManager.getInstance(_project) as PsiManagerEx).fileManager.createFileViewProvider(LightVirtualFile(name, KotlinFileType.INSTANCE, text), true), false), JavaCodeFragment {
|
) : KtFile(
|
||||||
|
(PsiManager.getInstance(_project) as PsiManagerEx).fileManager.createFileViewProvider(
|
||||||
|
LightVirtualFile(
|
||||||
|
name,
|
||||||
|
KotlinFileType.INSTANCE,
|
||||||
|
text
|
||||||
|
), true
|
||||||
|
), false
|
||||||
|
), JavaCodeFragment {
|
||||||
|
|
||||||
private var viewProvider = super.getViewProvider() as SingleRootFileViewProvider
|
private var viewProvider = super.getViewProvider() as SingleRootFileViewProvider
|
||||||
private var imports = LinkedHashSet<String>()
|
private var imports = LinkedHashSet<String>()
|
||||||
@@ -93,7 +101,8 @@ abstract class KtCodeFragment(
|
|||||||
clone.isPhysical = false
|
clone.isPhysical = false
|
||||||
clone.originalFile = this
|
clone.originalFile = this
|
||||||
clone.imports = imports
|
clone.imports = imports
|
||||||
clone.viewProvider = SingleRootFileViewProvider(PsiManager.getInstance(_project), LightVirtualFile(name, KotlinFileType.INSTANCE, text), false)
|
clone.viewProvider =
|
||||||
|
SingleRootFileViewProvider(PsiManager.getInstance(_project), LightVirtualFile(name, KotlinFileType.INSTANCE, text), false)
|
||||||
clone.viewProvider.forceCachedPsi(clone)
|
clone.viewProvider.forceCachedPsi(clone)
|
||||||
return clone
|
return clone
|
||||||
}
|
}
|
||||||
@@ -147,7 +156,7 @@ abstract class KtCodeFragment(
|
|||||||
override val importDirectives: List<KtImportDirective>
|
override val importDirectives: List<KtImportDirective>
|
||||||
get() = importsAsImportList()?.imports ?: emptyList()
|
get() = importsAsImportList()?.imports ?: emptyList()
|
||||||
|
|
||||||
override fun setVisibilityChecker(checker: JavaCodeFragment.VisibilityChecker?) { }
|
override fun setVisibilityChecker(checker: JavaCodeFragment.VisibilityChecker?) {}
|
||||||
|
|
||||||
override fun getVisibilityChecker() = JavaCodeFragment.VisibilityChecker.EVERYTHING_VISIBLE
|
override fun getVisibilityChecker() = JavaCodeFragment.VisibilityChecker.EVERYTHING_VISIBLE
|
||||||
|
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ abstract class KtConstructor<T : KtConstructor<T>> : KtDeclarationStub<KotlinPla
|
|||||||
|
|
||||||
override fun getTextOffset(): Int {
|
override fun getTextOffset(): Int {
|
||||||
return getConstructorKeyword()?.textOffset
|
return getConstructorKeyword()?.textOffset
|
||||||
?: valueParameterList?.textOffset
|
?: valueParameterList?.textOffset
|
||||||
?: super.getTextOffset()
|
?: super.getTextOffset()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getUseScope(): SearchScope {
|
override fun getUseScope(): SearchScope {
|
||||||
|
|||||||
@@ -58,15 +58,18 @@ class KtDotQualifiedExpression : KtExpressionImplStub<KotlinPlaceHolderStub<KtDo
|
|||||||
private fun getChildExpressionsByStub(stub: KotlinPlaceHolderStub<KtDotQualifiedExpression>): Array<KtExpression>? {
|
private fun getChildExpressionsByStub(stub: KotlinPlaceHolderStub<KtDotQualifiedExpression>): Array<KtExpression>? {
|
||||||
if (stub.getParentStubOfType(KtImportDirective::class.java) == null &&
|
if (stub.getParentStubOfType(KtImportDirective::class.java) == null &&
|
||||||
stub.getParentStubOfType(KtPackageDirective::class.java) == null) {
|
stub.getParentStubOfType(KtPackageDirective::class.java) == null) {
|
||||||
LOG.error("KtDotQualifiedExpression should only have stubs inside import or package directives.\n" +
|
LOG.error(
|
||||||
"Stubs were created for:\n$text\nFile text:\n${containingFile.text}")
|
"KtDotQualifiedExpression should only have stubs inside import or package directives.\n" +
|
||||||
|
"Stubs were created for:\n$text\nFile text:\n${containingFile.text}"
|
||||||
|
)
|
||||||
return null
|
return null
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val expressions = stub.getChildrenByType(INSIDE_DIRECTIVE_EXPRESSIONS, KtExpression.ARRAY_FACTORY)
|
val expressions = stub.getChildrenByType(INSIDE_DIRECTIVE_EXPRESSIONS, KtExpression.ARRAY_FACTORY)
|
||||||
if (expressions.size !in 1..2) {
|
if (expressions.size !in 1..2) {
|
||||||
LOG.error("Invalid stub structure. DOT_QUALIFIED_EXPRESSION must have one or two children. Was: ${expressions.size}\n" +
|
LOG.error(
|
||||||
"File text:\n${containingFile.text}")
|
"Invalid stub structure. DOT_QUALIFIED_EXPRESSION must have one or two children. Was: ${expressions.size}\n" +
|
||||||
|
"File text:\n${containingFile.text}"
|
||||||
|
)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return expressions
|
return expressions
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ import com.intellij.psi.PsiElement
|
|||||||
import org.jetbrains.kotlin.KtNodeTypes
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
|
|
||||||
class KtExpressionCodeFragment(
|
class KtExpressionCodeFragment(
|
||||||
project: Project,
|
project: Project,
|
||||||
name: String,
|
name: String,
|
||||||
text: CharSequence,
|
text: CharSequence,
|
||||||
imports: String?,
|
imports: String?,
|
||||||
context: PsiElement?
|
context: PsiElement?
|
||||||
) : KtCodeFragment(project, name, text, imports, KtNodeTypes.EXPRESSION_CODE_FRAGMENT, context) {
|
) : KtCodeFragment(project, name, text, imports, KtNodeTypes.EXPRESSION_CODE_FRAGMENT, context) {
|
||||||
|
|
||||||
override fun getContentElement() = findChildByClass(KtExpression::class.java)
|
override fun getContentElement() = findChildByClass(KtExpression::class.java)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
open class KtExpressionWithLabel(node: ASTNode) : KtExpressionImpl(node) {
|
open class KtExpressionWithLabel(node: ASTNode) : KtExpressionImpl(node) {
|
||||||
|
|
||||||
fun getTargetLabel(): KtSimpleNameExpression? =
|
fun getTargetLabel(): KtSimpleNameExpression? =
|
||||||
labelQualifier?.findChildByType(KtNodeTypes.LABEL) as? KtSimpleNameExpression
|
labelQualifier?.findChildByType(KtNodeTypes.LABEL) as? KtSimpleNameExpression
|
||||||
|
|
||||||
val labelQualifier: KtContainerNode?
|
val labelQualifier: KtContainerNode?
|
||||||
get() = findChildByType(KtNodeTypes.LABEL_QUALIFIER)
|
get() = findChildByType(KtNodeTypes.LABEL_QUALIFIER)
|
||||||
|
|||||||
@@ -36,13 +36,13 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtPlaceHolderStubElementType
|
|||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||||
|
|
||||||
open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) :
|
open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) :
|
||||||
PsiFileBase(viewProvider, KotlinLanguage.INSTANCE),
|
PsiFileBase(viewProvider, KotlinLanguage.INSTANCE),
|
||||||
KtDeclarationContainer,
|
KtDeclarationContainer,
|
||||||
KtAnnotated,
|
KtAnnotated,
|
||||||
KtElement,
|
KtElement,
|
||||||
PsiClassOwner,
|
PsiClassOwner,
|
||||||
PsiNamedElement,
|
PsiNamedElement,
|
||||||
PsiModifiableCodeBlock {
|
PsiModifiableCodeBlock {
|
||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
private var isScript: Boolean? = null
|
private var isScript: Boolean? = null
|
||||||
@@ -85,8 +85,7 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) :
|
|||||||
val packageDirective = packageDirective
|
val packageDirective = packageDirective
|
||||||
if (packageDirective != null) {
|
if (packageDirective != null) {
|
||||||
packageDirective.fqName = value
|
packageDirective.fqName = value
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val newPackageDirective = KtPsiFactory(this).createPackageDirectiveIfNeeded(value) ?: return
|
val newPackageDirective = KtPsiFactory(this).createPackageDirectiveIfNeeded(value) ?: return
|
||||||
addAfter(newPackageDirective, null)
|
addAfter(newPackageDirective, null)
|
||||||
}
|
}
|
||||||
@@ -126,8 +125,8 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) :
|
|||||||
get() {
|
get() {
|
||||||
val stub = stub
|
val stub = stub
|
||||||
val danglingModifierLists = stub?.getChildrenByType(
|
val danglingModifierLists = stub?.getChildrenByType(
|
||||||
KtStubElementTypes.MODIFIER_LIST,
|
KtStubElementTypes.MODIFIER_LIST,
|
||||||
KtStubElementTypes.MODIFIER_LIST.arrayFactory
|
KtStubElementTypes.MODIFIER_LIST.arrayFactory
|
||||||
) ?: findChildrenByClass(KtModifierList::class.java)
|
) ?: findChildrenByClass(KtModifierList::class.java)
|
||||||
return danglingModifierLists.flatMap { obj: KtModifierList -> obj.annotationEntries }
|
return danglingModifierLists.flatMap { obj: KtModifierList -> obj.annotationEntries }
|
||||||
}
|
}
|
||||||
@@ -139,12 +138,12 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) :
|
|||||||
override fun getDeclarations(): List<KtDeclaration> {
|
override fun getDeclarations(): List<KtDeclaration> {
|
||||||
val stub = stub
|
val stub = stub
|
||||||
return stub?.getChildrenByType(KtStubElementTypes.DECLARATION_TYPES, KtDeclaration.ARRAY_FACTORY)?.toList()
|
return stub?.getChildrenByType(KtStubElementTypes.DECLARATION_TYPES, KtDeclaration.ARRAY_FACTORY)?.toList()
|
||||||
?: PsiTreeUtil.getChildrenOfTypeAsList(this, KtDeclaration::class.java)
|
?: PsiTreeUtil.getChildrenOfTypeAsList(this, KtDeclaration::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : KtElementImplStub<out StubElement<*>>> findChildByTypeOrClass(
|
fun <T : KtElementImplStub<out StubElement<*>>> findChildByTypeOrClass(
|
||||||
elementType: KtPlaceHolderStubElementType<T>,
|
elementType: KtPlaceHolderStubElementType<T>,
|
||||||
elementClass: Class<T>
|
elementClass: Class<T>
|
||||||
): T? {
|
): T? {
|
||||||
val stub = stub
|
val stub = stub
|
||||||
if (stub != null) {
|
if (stub != null) {
|
||||||
@@ -155,7 +154,7 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun findImportByAlias(name: String): KtImportDirective? =
|
fun findImportByAlias(name: String): KtImportDirective? =
|
||||||
importDirectives.firstOrNull { name == it.aliasName }
|
importDirectives.firstOrNull { name == it.aliasName }
|
||||||
|
|
||||||
@Deprecated("") // getPackageFqName should be used instead
|
@Deprecated("") // getPackageFqName should be used instead
|
||||||
override fun getPackageName(): String {
|
override fun getPackageName(): String {
|
||||||
@@ -188,9 +187,9 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) :
|
|||||||
|
|
||||||
val result = declarations.any {
|
val result = declarations.any {
|
||||||
(it is KtProperty ||
|
(it is KtProperty ||
|
||||||
it is KtNamedFunction ||
|
it is KtNamedFunction ||
|
||||||
it is KtScript ||
|
it is KtScript ||
|
||||||
it is KtTypeAlias) && !it.hasExpectModifier()
|
it is KtTypeAlias) && !it.hasExpectModifier()
|
||||||
}
|
}
|
||||||
|
|
||||||
hasTopLeveCallables = result
|
hasTopLeveCallables = result
|
||||||
@@ -201,8 +200,7 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) :
|
|||||||
if (visitor is KtVisitor<*, *>) {
|
if (visitor is KtVisitor<*, *>) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
accept(visitor as KtVisitor<Any, Any?>, null)
|
accept(visitor as KtVisitor<Any, Any?>, null)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
visitor.visitFile(this)
|
visitor.visitFile(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,10 +216,10 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getAnnotations(): List<KtAnnotation> =
|
override fun getAnnotations(): List<KtAnnotation> =
|
||||||
fileAnnotationList?.annotations ?: emptyList()
|
fileAnnotationList?.annotations ?: emptyList()
|
||||||
|
|
||||||
override fun getAnnotationEntries(): List<KtAnnotationEntry> =
|
override fun getAnnotationEntries(): List<KtAnnotationEntry> =
|
||||||
fileAnnotationList?.annotationEntries ?: emptyList()
|
fileAnnotationList?.annotationEntries ?: emptyList()
|
||||||
|
|
||||||
@Throws(IncorrectOperationException::class)
|
@Throws(IncorrectOperationException::class)
|
||||||
override fun setName(name: String): PsiElement {
|
override fun setName(name: String): PsiElement {
|
||||||
|
|||||||
@@ -19,5 +19,5 @@ package org.jetbrains.kotlin.psi
|
|||||||
import com.intellij.lang.ASTNode
|
import com.intellij.lang.ASTNode
|
||||||
|
|
||||||
class KtLabelReferenceExpression(node: ASTNode) : KtSimpleNameExpressionImpl(node) {
|
class KtLabelReferenceExpression(node: ASTNode) : KtSimpleNameExpressionImpl(node) {
|
||||||
override fun getReferencedNameElement() = getIdentifier() ?: this
|
override fun getReferencedNameElement() = getIdentifier() ?: this
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,8 +49,7 @@ class KtObjectDeclaration : KtClassOrObject {
|
|||||||
addAfter(psiFactory.createWhiteSpace(), getObjectKeyword()!!)
|
addAfter(psiFactory.createWhiteSpace(), getObjectKeyword()!!)
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
super.setName(name)
|
super.setName(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +57,7 @@ class KtObjectDeclaration : KtClassOrObject {
|
|||||||
fun isCompanion(): Boolean = _stub?.isCompanion() ?: hasModifier(KtTokens.COMPANION_KEYWORD)
|
fun isCompanion(): Boolean = _stub?.isCompanion() ?: hasModifier(KtTokens.COMPANION_KEYWORD)
|
||||||
|
|
||||||
override fun getTextOffset(): Int = nameIdentifier?.textRange?.startOffset
|
override fun getTextOffset(): Int = nameIdentifier?.textRange?.startOffset
|
||||||
?: getObjectKeyword()!!.textRange.startOffset
|
?: getObjectKeyword()!!.textRange.startOffset
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: KtVisitor<R, D>, data: D): R {
|
override fun <R, D> accept(visitor: KtVisitor<R, D>, data: D): R {
|
||||||
return visitor.visitObjectDeclaration(this, data)
|
return visitor.visitObjectDeclaration(this, data)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
|||||||
* Underlying token is [org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE]
|
* Underlying token is [org.jetbrains.kotlin.KtNodeTypes.TYPE_REFERENCE]
|
||||||
*/
|
*/
|
||||||
class KtTypeReference : KtModifierListOwnerStub<KotlinPlaceHolderStub<KtTypeReference>>,
|
class KtTypeReference : KtModifierListOwnerStub<KotlinPlaceHolderStub<KtTypeReference>>,
|
||||||
KtAnnotated, KtAnnotationsContainer {
|
KtAnnotated, KtAnnotationsContainer {
|
||||||
|
|
||||||
constructor(node: ASTNode) : super(node)
|
constructor(node: ASTNode) : super(node)
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
|||||||
|
|
||||||
fun getTypeReference(declaration: KtCallableDeclaration): KtTypeReference? {
|
fun getTypeReference(declaration: KtCallableDeclaration): KtTypeReference? {
|
||||||
return declaration.firstChild!!.siblings(forward = true)
|
return declaration.firstChild!!.siblings(forward = true)
|
||||||
.dropWhile { it.node!!.elementType != KtTokens.COLON }
|
.dropWhile { it.node!!.elementType != KtTokens.COLON }
|
||||||
.firstIsInstanceOrNull<KtTypeReference>()
|
.firstIsInstanceOrNull<KtTypeReference>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setTypeReference(declaration: KtCallableDeclaration, addAfter: PsiElement?, typeRef: KtTypeReference?): KtTypeReference? {
|
fun setTypeReference(declaration: KtCallableDeclaration, addAfter: PsiElement?, typeRef: KtTypeReference?): KtTypeReference? {
|
||||||
@@ -36,17 +36,15 @@ fun setTypeReference(declaration: KtCallableDeclaration, addAfter: PsiElement?,
|
|||||||
if (typeRef != null) {
|
if (typeRef != null) {
|
||||||
return if (oldTypeRef != null) {
|
return if (oldTypeRef != null) {
|
||||||
oldTypeRef.replace(typeRef) as KtTypeReference
|
oldTypeRef.replace(typeRef) as KtTypeReference
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val anchor = addAfter
|
val anchor = addAfter
|
||||||
?: declaration.nameIdentifier?.siblings(forward = true)?.firstOrNull { it is PsiErrorElement }
|
?: declaration.nameIdentifier?.siblings(forward = true)?.firstOrNull { it is PsiErrorElement }
|
||||||
?: (declaration as? KtParameter)?.destructuringDeclaration
|
?: (declaration as? KtParameter)?.destructuringDeclaration
|
||||||
val newTypeRef = declaration.addAfter(typeRef, anchor) as KtTypeReference
|
val newTypeRef = declaration.addAfter(typeRef, anchor) as KtTypeReference
|
||||||
declaration.addAfter(KtPsiFactory(declaration.project).createColon(), anchor)
|
declaration.addAfter(KtPsiFactory(declaration.project).createColon(), anchor)
|
||||||
newTypeRef
|
newTypeRef
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (oldTypeRef != null) {
|
if (oldTypeRef != null) {
|
||||||
val colon = declaration.colon!!
|
val colon = declaration.colon!!
|
||||||
val removeFrom = colon.prevSibling as? PsiWhiteSpace ?: colon
|
val removeFrom = colon.prevSibling as? PsiWhiteSpace ?: colon
|
||||||
@@ -57,30 +55,28 @@ fun setTypeReference(declaration: KtCallableDeclaration, addAfter: PsiElement?,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <T : KtElement> T.doSetReceiverTypeReference(
|
private inline fun <T : KtElement> T.doSetReceiverTypeReference(
|
||||||
typeRef: KtTypeReference?,
|
typeRef: KtTypeReference?,
|
||||||
getReceiverTypeReference: T.() -> KtTypeReference?,
|
getReceiverTypeReference: T.() -> KtTypeReference?,
|
||||||
addReceiverTypeReference: T.(typeRef: KtTypeReference) -> KtTypeReference
|
addReceiverTypeReference: T.(typeRef: KtTypeReference) -> KtTypeReference
|
||||||
): KtTypeReference? {
|
): KtTypeReference? {
|
||||||
val needParentheses = typeRef != null && typeRef.typeElement is KtFunctionType && !typeRef.hasParentheses()
|
val needParentheses = typeRef != null && typeRef.typeElement is KtFunctionType && !typeRef.hasParentheses()
|
||||||
val oldTypeRef = getReceiverTypeReference()
|
val oldTypeRef = getReceiverTypeReference()
|
||||||
if (typeRef != null) {
|
if (typeRef != null) {
|
||||||
val newTypeRef =
|
val newTypeRef =
|
||||||
if (oldTypeRef != null) {
|
if (oldTypeRef != null) {
|
||||||
oldTypeRef.replace(typeRef) as KtTypeReference
|
oldTypeRef.replace(typeRef) as KtTypeReference
|
||||||
}
|
} else {
|
||||||
else {
|
val newTypeRef = addReceiverTypeReference(typeRef)
|
||||||
val newTypeRef = addReceiverTypeReference(typeRef)
|
addAfter(KtPsiFactory(project).createDot(), newTypeRef.parentsWithSelf.first { it.parent == this })
|
||||||
addAfter(KtPsiFactory(project).createDot(), newTypeRef.parentsWithSelf.first { it.parent == this })
|
newTypeRef
|
||||||
newTypeRef
|
}
|
||||||
}
|
|
||||||
if (needParentheses) {
|
if (needParentheses) {
|
||||||
val argList = KtPsiFactory(project).createCallArguments("()")
|
val argList = KtPsiFactory(project).createCallArguments("()")
|
||||||
newTypeRef.addBefore(argList.leftParenthesis!!, newTypeRef.firstChild)
|
newTypeRef.addBefore(argList.leftParenthesis!!, newTypeRef.firstChild)
|
||||||
newTypeRef.add(argList.rightParenthesis!!)
|
newTypeRef.add(argList.rightParenthesis!!)
|
||||||
}
|
}
|
||||||
return newTypeRef
|
return newTypeRef
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (oldTypeRef != null) {
|
if (oldTypeRef != null) {
|
||||||
val dotSibling = oldTypeRef.parent as? KtFunctionTypeReceiver ?: oldTypeRef
|
val dotSibling = oldTypeRef.parent as? KtFunctionTypeReceiver ?: oldTypeRef
|
||||||
val dot = dotSibling.siblings(forward = true).firstOrNull { it.node.elementType == KtTokens.DOT }
|
val dot = dotSibling.siblings(forward = true).firstOrNull { it.node.elementType == KtTokens.DOT }
|
||||||
@@ -91,18 +87,20 @@ private inline fun <T : KtElement> T.doSetReceiverTypeReference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun KtCallableDeclaration.setReceiverTypeReference(typeRef: KtTypeReference?) =
|
fun KtCallableDeclaration.setReceiverTypeReference(typeRef: KtTypeReference?) =
|
||||||
doSetReceiverTypeReference(
|
doSetReceiverTypeReference(
|
||||||
typeRef,
|
typeRef,
|
||||||
{ receiverTypeReference },
|
{ receiverTypeReference },
|
||||||
{ this.addBefore(it, nameIdentifier ?: valueParameterList) as KtTypeReference }
|
{ this.addBefore(it, nameIdentifier ?: valueParameterList) as KtTypeReference }
|
||||||
)
|
)
|
||||||
|
|
||||||
fun KtFunctionType.setReceiverTypeReference(typeRef: KtTypeReference?) =
|
fun KtFunctionType.setReceiverTypeReference(typeRef: KtTypeReference?) =
|
||||||
doSetReceiverTypeReference(
|
doSetReceiverTypeReference(
|
||||||
typeRef,
|
typeRef,
|
||||||
{ receiverTypeReference },
|
{ receiverTypeReference },
|
||||||
{
|
{
|
||||||
(addBefore(KtPsiFactory(project).createFunctionTypeReceiver(it),
|
(addBefore(
|
||||||
parameterList ?: firstChild) as KtFunctionTypeReceiver).typeReference
|
KtPsiFactory(project).createFunctionTypeReceiver(it),
|
||||||
}
|
parameterList ?: firstChild
|
||||||
)
|
) as KtFunctionTypeReceiver).typeReference
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -20,7 +20,8 @@ import com.intellij.psi.impl.source.tree.LeafPsiElement
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
interface ValueArgument {
|
interface ValueArgument {
|
||||||
@IfNotParsed fun getArgumentExpression(): KtExpression?
|
@IfNotParsed
|
||||||
|
fun getArgumentExpression(): KtExpression?
|
||||||
|
|
||||||
fun getArgumentName(): ValueArgumentName?
|
fun getArgumentName(): ValueArgumentName?
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -23,7 +23,11 @@ import org.jetbrains.kotlin.psi.KtPsiFactory
|
|||||||
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||||
|
|
||||||
class KtStringTemplateExpressionManipulator : AbstractElementManipulator<KtStringTemplateExpression>() {
|
class KtStringTemplateExpressionManipulator : AbstractElementManipulator<KtStringTemplateExpression>() {
|
||||||
override fun handleContentChange(element: KtStringTemplateExpression, range: TextRange, newContent: String): KtStringTemplateExpression? {
|
override fun handleContentChange(
|
||||||
|
element: KtStringTemplateExpression,
|
||||||
|
range: TextRange,
|
||||||
|
newContent: String
|
||||||
|
): KtStringTemplateExpression? {
|
||||||
val node = element.node
|
val node = element.node
|
||||||
val content = if (element.isSingleQuoted()) StringUtil.escapeStringCharacters(newContent) else newContent
|
val content = if (element.isSingleQuoted()) StringUtil.escapeStringCharacters(newContent) else newContent
|
||||||
val oldText = node.text
|
val oldText = node.text
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ data class PsiChildRange(val first: PsiElement?, val last: PsiElement?) : Sequen
|
|||||||
init {
|
init {
|
||||||
if (first == null) {
|
if (first == null) {
|
||||||
assert(last == null)
|
assert(last == null)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
assert(first.parent == last!!.parent)
|
assert(first.parent == last!!.parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,8 +33,7 @@ data class PsiChildRange(val first: PsiElement?, val last: PsiElement?) : Sequen
|
|||||||
override fun iterator(): Iterator<PsiElement> {
|
override fun iterator(): Iterator<PsiElement> {
|
||||||
val sequence = if (first == null) {
|
val sequence = if (first == null) {
|
||||||
emptySequence<PsiElement>()
|
emptySequence<PsiElement>()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val afterLast = last!!.nextSibling
|
val afterLast = last!!.nextSibling
|
||||||
first.siblings().takeWhile { it != afterLast }
|
first.siblings().takeWhile { it != afterLast }
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -22,8 +22,12 @@ import com.intellij.openapi.util.TextRange
|
|||||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
|
|
||||||
class StringTemplateExpressionManipulator: AbstractElementManipulator<KtStringTemplateExpression>() {
|
class StringTemplateExpressionManipulator : AbstractElementManipulator<KtStringTemplateExpression>() {
|
||||||
override fun handleContentChange(element: KtStringTemplateExpression, range: TextRange, newContent: String): KtStringTemplateExpression? {
|
override fun handleContentChange(
|
||||||
|
element: KtStringTemplateExpression,
|
||||||
|
range: TextRange,
|
||||||
|
newContent: String
|
||||||
|
): KtStringTemplateExpression? {
|
||||||
val node = element.node
|
val node = element.node
|
||||||
val content = if (node.firstChildNode.textLength == 1) StringUtil.escapeStringCharacters(newContent) else newContent
|
val content = if (node.firstChildNode.textLength == 1) StringUtil.escapeStringCharacters(newContent) else newContent
|
||||||
val oldText = node.text
|
val oldText = node.text
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.psi.stubs.KotlinScriptStub
|
|||||||
import org.jetbrains.kotlin.psi.stubs.impl.KotlinScriptStubImpl
|
import org.jetbrains.kotlin.psi.stubs.impl.KotlinScriptStubImpl
|
||||||
|
|
||||||
class KtScriptElementType(debugName: String) : KtStubElementType<KotlinScriptStub, KtScript>(
|
class KtScriptElementType(debugName: String) : KtStubElementType<KotlinScriptStub, KtScript>(
|
||||||
debugName, KtScript::class.java, KotlinScriptStub::class.java
|
debugName, KtScript::class.java, KotlinScriptStub::class.java
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun createStub(psi: KtScript, parentStub: StubElement<PsiElement>): KotlinScriptStub {
|
override fun createStub(psi: KtScript, parentStub: StubElement<PsiElement>): KotlinScriptStub {
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.psi.stubs.impl.KotlinTypeAliasStubImpl
|
|||||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils
|
import org.jetbrains.kotlin.resolve.lazy.ResolveSessionUtils
|
||||||
|
|
||||||
class KtTypeAliasElementType(debugName: String) :
|
class KtTypeAliasElementType(debugName: String) :
|
||||||
KtStubElementType<KotlinTypeAliasStub, KtTypeAlias>(debugName, KtTypeAlias::class.java, KotlinTypeAliasStub::class.java) {
|
KtStubElementType<KotlinTypeAliasStub, KtTypeAlias>(debugName, KtTypeAlias::class.java, KotlinTypeAliasStub::class.java) {
|
||||||
|
|
||||||
override fun createStub(psi: KtTypeAlias, parentStub: StubElement<*>?): KotlinTypeAliasStub {
|
override fun createStub(psi: KtTypeAlias, parentStub: StubElement<*>?): KotlinTypeAliasStub {
|
||||||
val name = StringRef.fromString(psi.name)
|
val name = StringRef.fromString(psi.name)
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ open class StubIndexService protected constructor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic fun getInstance(): StubIndexService {
|
@JvmStatic
|
||||||
|
fun getInstance(): StubIndexService {
|
||||||
return ServiceManager.getService(StubIndexService::class.java) ?: NO_INDEX
|
return ServiceManager.getService(StubIndexService::class.java) ?: NO_INDEX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,15 +26,15 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtClassElementType
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class KotlinClassStubImpl(
|
class KotlinClassStubImpl(
|
||||||
type: KtClassElementType,
|
type: KtClassElementType,
|
||||||
parent: StubElement<out PsiElement>?,
|
parent: StubElement<out PsiElement>?,
|
||||||
private val qualifiedName: StringRef?,
|
private val qualifiedName: StringRef?,
|
||||||
private val name: StringRef?,
|
private val name: StringRef?,
|
||||||
private val superNames: Array<StringRef>,
|
private val superNames: Array<StringRef>,
|
||||||
private val isInterface: Boolean,
|
private val isInterface: Boolean,
|
||||||
private val isEnumEntry: Boolean,
|
private val isEnumEntry: Boolean,
|
||||||
private val isLocal: Boolean,
|
private val isLocal: Boolean,
|
||||||
private val isTopLevel: Boolean
|
private val isTopLevel: Boolean
|
||||||
) : KotlinStubBaseImpl<KtClass>(parent, type), KotlinClassStub {
|
) : KotlinStubBaseImpl<KtClass>(parent, type), KotlinClassStub {
|
||||||
|
|
||||||
override fun getFqName(): FqName? {
|
override fun getFqName(): FqName? {
|
||||||
|
|||||||
+3
-2
@@ -22,8 +22,9 @@ import org.jetbrains.kotlin.psi.KtEnumEntrySuperclassReferenceExpression
|
|||||||
import org.jetbrains.kotlin.psi.stubs.KotlinEnumEntrySuperclassReferenceExpressionStub
|
import org.jetbrains.kotlin.psi.stubs.KotlinEnumEntrySuperclassReferenceExpressionStub
|
||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||||
|
|
||||||
class KotlinEnumEntrySuperclassReferenceExpressionStubImpl(parent: StubElement<*>, private val referencedName: StringRef)
|
class KotlinEnumEntrySuperclassReferenceExpressionStubImpl(parent: StubElement<*>, private val referencedName: StringRef) :
|
||||||
: KotlinStubBaseImpl<KtEnumEntrySuperclassReferenceExpression>(parent, KtStubElementTypes.ENUM_ENTRY_SUPERCLASS_REFERENCE_EXPRESSION), KotlinEnumEntrySuperclassReferenceExpressionStub {
|
KotlinStubBaseImpl<KtEnumEntrySuperclassReferenceExpression>(parent, KtStubElementTypes.ENUM_ENTRY_SUPERCLASS_REFERENCE_EXPRESSION),
|
||||||
|
KotlinEnumEntrySuperclassReferenceExpressionStub {
|
||||||
|
|
||||||
override fun getReferencedName() = referencedName.string
|
override fun getReferencedName() = referencedName.string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,13 +32,13 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes.IMPORT_LIST
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
|
|
||||||
open class KotlinFileStubImpl(
|
open class KotlinFileStubImpl(
|
||||||
jetFile: KtFile?,
|
jetFile: KtFile?,
|
||||||
private val packageName: StringRef,
|
private val packageName: StringRef,
|
||||||
private val isScript: Boolean
|
private val isScript: Boolean
|
||||||
) : PsiFileStubImpl<KtFile>(jetFile), KotlinFileStub, PsiClassHolderFileStub<KtFile> {
|
) : PsiFileStubImpl<KtFile>(jetFile), KotlinFileStub, PsiClassHolderFileStub<KtFile> {
|
||||||
|
|
||||||
constructor(jetFile: KtFile?, packageName: String, isScript: Boolean)
|
constructor(jetFile: KtFile?, packageName: String, isScript: Boolean)
|
||||||
: this(jetFile, StringRef.fromString(packageName)!!, isScript)
|
: this(jetFile, StringRef.fromString(packageName)!!, isScript)
|
||||||
|
|
||||||
override fun getPackageFqName(): FqName = FqName(StringRef.toString(packageName)!!)
|
override fun getPackageFqName(): FqName = FqName(StringRef.toString(packageName)!!)
|
||||||
override fun isScript(): Boolean = isScript
|
override fun isScript(): Boolean = isScript
|
||||||
|
|||||||
+2
-2
@@ -24,8 +24,8 @@ import org.jetbrains.kotlin.psi.stubs.KotlinImportAliasStub
|
|||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||||
|
|
||||||
class KotlinImportAliasStubImpl(
|
class KotlinImportAliasStubImpl(
|
||||||
parent: StubElement<PsiElement>?,
|
parent: StubElement<PsiElement>?,
|
||||||
private val name: StringRef?
|
private val name: StringRef?
|
||||||
) : KotlinStubBaseImpl<KtImportAlias>(parent, KtStubElementTypes.IMPORT_ALIAS), KotlinImportAliasStub {
|
) : KotlinStubBaseImpl<KtImportAlias>(parent, KtStubElementTypes.IMPORT_ALIAS), KotlinImportAliasStub {
|
||||||
override fun getName(): String? = StringRef.toString(name)
|
override fun getName(): String? = StringRef.toString(name)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -25,10 +25,10 @@ import org.jetbrains.kotlin.psi.stubs.KotlinImportDirectiveStub
|
|||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||||
|
|
||||||
class KotlinImportDirectiveStubImpl(
|
class KotlinImportDirectiveStubImpl(
|
||||||
parent: StubElement<PsiElement>,
|
parent: StubElement<PsiElement>,
|
||||||
private val isAllUnder: Boolean,
|
private val isAllUnder: Boolean,
|
||||||
private val importedFqName: StringRef?,
|
private val importedFqName: StringRef?,
|
||||||
private val isValid: Boolean
|
private val isValid: Boolean
|
||||||
) : KotlinStubBaseImpl<KtImportDirective>(parent, KtStubElementTypes.IMPORT_DIRECTIVE), KotlinImportDirectiveStub {
|
) : KotlinStubBaseImpl<KtImportDirective>(parent, KtStubElementTypes.IMPORT_DIRECTIVE), KotlinImportDirectiveStub {
|
||||||
override fun isAllUnder(): Boolean = isAllUnder
|
override fun isAllUnder(): Boolean = isAllUnder
|
||||||
|
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
|
||||||
class KotlinObjectStubImpl(
|
class KotlinObjectStubImpl(
|
||||||
parent: StubElement<out PsiElement>?,
|
parent: StubElement<out PsiElement>?,
|
||||||
private val name: StringRef?,
|
private val name: StringRef?,
|
||||||
private val fqName: FqName?,
|
private val fqName: FqName?,
|
||||||
private val superNames: Array<StringRef>,
|
private val superNames: Array<StringRef>,
|
||||||
private val isTopLevel: Boolean,
|
private val isTopLevel: Boolean,
|
||||||
private val isDefault: Boolean,
|
private val isDefault: Boolean,
|
||||||
private val isLocal: Boolean,
|
private val isLocal: Boolean,
|
||||||
private val isObjectLiteral: Boolean
|
private val isObjectLiteral: Boolean
|
||||||
) : KotlinStubBaseImpl<KtObjectDeclaration>(parent, KtStubElementTypes.OBJECT_DECLARATION), KotlinObjectStub {
|
) : KotlinStubBaseImpl<KtObjectDeclaration>(parent, KtStubElementTypes.OBJECT_DECLARATION), KotlinObjectStub {
|
||||||
override fun getFqName() = fqName
|
override fun getFqName() = fqName
|
||||||
override fun getName() = StringRef.toString(name)
|
override fun getName() = StringRef.toString(name)
|
||||||
|
|||||||
+10
-10
@@ -25,16 +25,16 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
|
||||||
class KotlinPropertyStubImpl(
|
class KotlinPropertyStubImpl(
|
||||||
parent: StubElement<out PsiElement>?,
|
parent: StubElement<out PsiElement>?,
|
||||||
private val name: StringRef?,
|
private val name: StringRef?,
|
||||||
private val isVar: Boolean,
|
private val isVar: Boolean,
|
||||||
private val isTopLevel: Boolean,
|
private val isTopLevel: Boolean,
|
||||||
private val hasDelegate: Boolean,
|
private val hasDelegate: Boolean,
|
||||||
private val hasDelegateExpression: Boolean,
|
private val hasDelegateExpression: Boolean,
|
||||||
private val hasInitializer: Boolean,
|
private val hasInitializer: Boolean,
|
||||||
private val isExtension: Boolean,
|
private val isExtension: Boolean,
|
||||||
private val hasReturnTypeRef: Boolean,
|
private val hasReturnTypeRef: Boolean,
|
||||||
private val fqName: FqName?
|
private val fqName: FqName?
|
||||||
) : KotlinStubBaseImpl<KtProperty>(parent, KtStubElementTypes.PROPERTY), KotlinPropertyStub {
|
) : KotlinStubBaseImpl<KtProperty>(parent, KtStubElementTypes.PROPERTY), KotlinPropertyStub {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ import org.jetbrains.kotlin.psi.stubs.KotlinScriptStub
|
|||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||||
|
|
||||||
class KotlinScriptStubImpl(
|
class KotlinScriptStubImpl(
|
||||||
parent: StubElement<out PsiElement>?,
|
parent: StubElement<out PsiElement>?,
|
||||||
private val _fqName: StringRef?
|
private val _fqName: StringRef?
|
||||||
) : KotlinStubBaseImpl<KtScript>(parent, KtStubElementTypes.SCRIPT), KotlinScriptStub {
|
) : KotlinStubBaseImpl<KtScript>(parent, KtStubElementTypes.SCRIPT), KotlinScriptStub {
|
||||||
override fun getName(): String = getFqName().shortName().asString()
|
override fun getName(): String = getFqName().shortName().asString()
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -25,17 +25,17 @@ import org.jetbrains.kotlin.psi.stubs.KotlinTypeAliasStub
|
|||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||||
|
|
||||||
class KotlinTypeAliasStubImpl(
|
class KotlinTypeAliasStubImpl(
|
||||||
parent: StubElement<out PsiElement>?,
|
parent: StubElement<out PsiElement>?,
|
||||||
private val name: StringRef?,
|
private val name: StringRef?,
|
||||||
private val qualifiedName: StringRef?,
|
private val qualifiedName: StringRef?,
|
||||||
private val isTopLevel: Boolean
|
private val isTopLevel: Boolean
|
||||||
) : KotlinStubBaseImpl<KtTypeAlias>(parent, KtStubElementTypes.TYPEALIAS), KotlinTypeAliasStub {
|
) : KotlinStubBaseImpl<KtTypeAlias>(parent, KtStubElementTypes.TYPEALIAS), KotlinTypeAliasStub {
|
||||||
|
|
||||||
override fun getName(): String? =
|
override fun getName(): String? =
|
||||||
StringRef.toString(name)
|
StringRef.toString(name)
|
||||||
|
|
||||||
override fun getFqName(): FqName? =
|
override fun getFqName(): FqName? =
|
||||||
StringRef.toString(qualifiedName)?.let(::FqName)
|
StringRef.toString(qualifiedName)?.let(::FqName)
|
||||||
|
|
||||||
override fun isTopLevel(): Boolean = isTopLevel
|
override fun isTopLevel(): Boolean = isTopLevel
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -24,10 +24,10 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
|
||||||
class KotlinTypeParameterStubImpl(
|
class KotlinTypeParameterStubImpl(
|
||||||
parent: StubElement<out PsiElement>?,
|
parent: StubElement<out PsiElement>?,
|
||||||
private val name: StringRef?,
|
private val name: StringRef?,
|
||||||
private val isInVariance: Boolean,
|
private val isInVariance: Boolean,
|
||||||
private val isOutVariance: Boolean
|
private val isOutVariance: Boolean
|
||||||
) : KotlinStubBaseImpl<KtTypeParameter>(parent, KtStubElementTypes.TYPE_PARAMETER), KotlinTypeParameterStub {
|
) : KotlinStubBaseImpl<KtTypeParameter>(parent, KtStubElementTypes.TYPE_PARAMETER), KotlinTypeParameterStub {
|
||||||
override fun isInVariance() = isInVariance
|
override fun isInVariance() = isInVariance
|
||||||
override fun isOutVariance() = isOutVariance
|
override fun isOutVariance() = isOutVariance
|
||||||
|
|||||||
@@ -26,9 +26,11 @@ object ModifierMaskUtils {
|
|||||||
assert(MODIFIER_KEYWORDS_ARRAY.size <= 32) { "Current implementation depends on the ability to represent modifier list as bit mask" }
|
assert(MODIFIER_KEYWORDS_ARRAY.size <= 32) { "Current implementation depends on the ability to represent modifier list as bit mask" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun computeMaskFromModifierList(modifierList: KtModifierList): Int = computeMask { modifierList.hasModifier(it) }
|
@JvmStatic
|
||||||
|
fun computeMaskFromModifierList(modifierList: KtModifierList): Int = computeMask { modifierList.hasModifier(it) }
|
||||||
|
|
||||||
@JvmStatic fun computeMask(hasModifier: (KtModifierKeywordToken) -> Boolean): Int {
|
@JvmStatic
|
||||||
|
fun computeMask(hasModifier: (KtModifierKeywordToken) -> Boolean): Int {
|
||||||
var mask = 0
|
var mask = 0
|
||||||
for ((index, modifierKeywordToken) in MODIFIER_KEYWORDS_ARRAY.withIndex()) {
|
for ((index, modifierKeywordToken) in MODIFIER_KEYWORDS_ARRAY.withIndex()) {
|
||||||
if (hasModifier(modifierKeywordToken)) {
|
if (hasModifier(modifierKeywordToken)) {
|
||||||
@@ -38,13 +40,15 @@ object ModifierMaskUtils {
|
|||||||
return mask
|
return mask
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun maskHasModifier(mask: Int, modifierToken: KtModifierKeywordToken): Boolean {
|
@JvmStatic
|
||||||
|
fun maskHasModifier(mask: Int, modifierToken: KtModifierKeywordToken): Boolean {
|
||||||
val index = MODIFIER_KEYWORDS_ARRAY.indexOf(modifierToken)
|
val index = MODIFIER_KEYWORDS_ARRAY.indexOf(modifierToken)
|
||||||
assert(index >= 0) { "All JetModifierKeywordTokens should be present in MODIFIER_KEYWORDS_ARRAY" }
|
assert(index >= 0) { "All JetModifierKeywordTokens should be present in MODIFIER_KEYWORDS_ARRAY" }
|
||||||
return (mask and (1 shl index)) != 0
|
return (mask and (1 shl index)) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun maskToString(mask: Int): String {
|
@JvmStatic
|
||||||
|
fun maskToString(mask: Int): String {
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
sb.append("[")
|
sb.append("[")
|
||||||
var first = true
|
var first = true
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ import org.jetbrains.kotlin.util.slicedMap.WritableSlice
|
|||||||
* (like storing them in the local map, later re-committing into parent's, etc.)
|
* (like storing them in the local map, later re-committing into parent's, etc.)
|
||||||
*/
|
*/
|
||||||
abstract class AbstractFilteringTrace(
|
abstract class AbstractFilteringTrace(
|
||||||
private val parentTrace: BindingTrace,
|
private val parentTrace: BindingTrace,
|
||||||
name: String
|
name: String
|
||||||
) : DelegatingBindingTrace(parentTrace.bindingContext, name, true, BindingTraceFilter.ACCEPT_ALL, false) {
|
) : DelegatingBindingTrace(parentTrace.bindingContext, name, true, BindingTraceFilter.ACCEPT_ALL, false) {
|
||||||
abstract protected fun <K, V> shouldBeHiddenFromParent(slice: WritableSlice<K, V>, key: K): Boolean
|
abstract protected fun <K, V> shouldBeHiddenFromParent(slice: WritableSlice<K, V>, key: K): Boolean
|
||||||
|
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
|||||||
import org.jetbrains.kotlin.types.isError
|
import org.jetbrains.kotlin.types.isError
|
||||||
|
|
||||||
class AnnotationChecker(
|
class AnnotationChecker(
|
||||||
private val additionalCheckers: Iterable<AdditionalAnnotationChecker>,
|
private val additionalCheckers: Iterable<AdditionalAnnotationChecker>,
|
||||||
private val languageVersionSettings: LanguageVersionSettings
|
private val languageVersionSettings: LanguageVersionSettings
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun check(annotated: KtAnnotated, trace: BindingTrace, descriptor: DeclarationDescriptor? = null) {
|
fun check(annotated: KtAnnotated, trace: BindingTrace, descriptor: DeclarationDescriptor? = null) {
|
||||||
@@ -86,25 +86,25 @@ class AnnotationChecker(
|
|||||||
|
|
||||||
private fun KtAnnotated?.getImplicitUseSiteTargetList(): List<AnnotationUseSiteTarget> = when (this) {
|
private fun KtAnnotated?.getImplicitUseSiteTargetList(): List<AnnotationUseSiteTarget> = when (this) {
|
||||||
is KtParameter ->
|
is KtParameter ->
|
||||||
if (ownerFunction is KtPrimaryConstructor) UseSiteTargetsList.T_CONSTRUCTOR_PARAMETER else emptyList()
|
if (ownerFunction is KtPrimaryConstructor) UseSiteTargetsList.T_CONSTRUCTOR_PARAMETER else emptyList()
|
||||||
is KtProperty ->
|
is KtProperty ->
|
||||||
if (!isLocal) UseSiteTargetsList.T_PROPERTY else emptyList()
|
if (!isLocal) UseSiteTargetsList.T_PROPERTY else emptyList()
|
||||||
is KtPropertyAccessor ->
|
is KtPropertyAccessor ->
|
||||||
if (isGetter) listOf(AnnotationUseSiteTarget.PROPERTY_GETTER) else listOf(AnnotationUseSiteTarget.PROPERTY_SETTER)
|
if (isGetter) listOf(AnnotationUseSiteTarget.PROPERTY_GETTER) else listOf(AnnotationUseSiteTarget.PROPERTY_SETTER)
|
||||||
else ->
|
else ->
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtAnnotated?.getDefaultUseSiteTarget(descriptor: AnnotationDescriptor) =
|
private fun KtAnnotated?.getDefaultUseSiteTarget(descriptor: AnnotationDescriptor) =
|
||||||
getImplicitUseSiteTargetList().firstOrNull {
|
getImplicitUseSiteTargetList().firstOrNull {
|
||||||
KotlinTarget.USE_SITE_MAPPING[it] in AnnotationChecker.applicableTargetSet(descriptor)
|
KotlinTarget.USE_SITE_MAPPING[it] in AnnotationChecker.applicableTargetSet(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkEntries(
|
private fun checkEntries(
|
||||||
entries: List<KtAnnotationEntry>,
|
entries: List<KtAnnotationEntry>,
|
||||||
actualTargets: TargetList,
|
actualTargets: TargetList,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
annotated: KtAnnotated? = null
|
annotated: KtAnnotated? = null
|
||||||
) {
|
) {
|
||||||
val entryTypesWithAnnotations = hashMapOf<KotlinType, MutableList<AnnotationUseSiteTarget?>>()
|
val entryTypesWithAnnotations = hashMapOf<KotlinType, MutableList<AnnotationUseSiteTarget?>>()
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ class AnnotationChecker(
|
|||||||
val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget() ?: annotated.getDefaultUseSiteTarget(descriptor)
|
val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget() ?: annotated.getDefaultUseSiteTarget(descriptor)
|
||||||
val existingTargetsForAnnotation = entryTypesWithAnnotations.getOrPut(descriptor.type) { arrayListOf() }
|
val existingTargetsForAnnotation = entryTypesWithAnnotations.getOrPut(descriptor.type) { arrayListOf() }
|
||||||
val duplicateAnnotation = useSiteTarget in existingTargetsForAnnotation
|
val duplicateAnnotation = useSiteTarget in existingTargetsForAnnotation
|
||||||
|| (existingTargetsForAnnotation.any { (it == null) != (useSiteTarget == null) })
|
|| (existingTargetsForAnnotation.any { (it == null) != (useSiteTarget == null) })
|
||||||
|
|
||||||
if (duplicateAnnotation && !classDescriptor.isRepeatableAnnotation()) {
|
if (duplicateAnnotation && !classDescriptor.isRepeatableAnnotation()) {
|
||||||
trace.report(Errors.REPEATED_ANNOTATION.on(entry))
|
trace.report(Errors.REPEATED_ANNOTATION.on(entry))
|
||||||
@@ -174,12 +174,17 @@ class AnnotationChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (useSiteTarget != null) {
|
if (useSiteTarget != null) {
|
||||||
trace.report(Errors.WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET.on(
|
trace.report(
|
||||||
entry, actualTargets.defaultTargets.firstOrNull()?.description ?: "unidentified target", useSiteTarget.renderName))
|
Errors.WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET.on(
|
||||||
}
|
entry, actualTargets.defaultTargets.firstOrNull()?.description ?: "unidentified target", useSiteTarget.renderName
|
||||||
else {
|
)
|
||||||
trace.report(Errors.WRONG_ANNOTATION_TARGET.on(
|
)
|
||||||
entry, actualTargets.defaultTargets.firstOrNull()?.description ?: "unidentified target"))
|
} else {
|
||||||
|
trace.report(
|
||||||
|
Errors.WRONG_ANNOTATION_TARGET.on(
|
||||||
|
entry, actualTargets.defaultTargets.firstOrNull()?.description ?: "unidentified target"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,14 +196,15 @@ class AnnotationChecker(
|
|||||||
return descriptor.annotationClass?.let(this::applicableTargetSet) ?: KotlinTarget.DEFAULT_TARGET_SET
|
return descriptor.annotationClass?.let(this::applicableTargetSet) ?: KotlinTarget.DEFAULT_TARGET_SET
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun applicableTargetSet(descriptor: AnnotationDescriptor): Set<KotlinTarget> {
|
@JvmStatic
|
||||||
|
fun applicableTargetSet(descriptor: AnnotationDescriptor): Set<KotlinTarget> {
|
||||||
val classDescriptor = descriptor.annotationClass ?: return emptySet()
|
val classDescriptor = descriptor.annotationClass ?: return emptySet()
|
||||||
return applicableTargetSet(classDescriptor) ?: KotlinTarget.DEFAULT_TARGET_SET
|
return applicableTargetSet(classDescriptor) ?: KotlinTarget.DEFAULT_TARGET_SET
|
||||||
}
|
}
|
||||||
|
|
||||||
fun applicableTargetSet(classDescriptor: ClassDescriptor): Set<KotlinTarget>? {
|
fun applicableTargetSet(classDescriptor: ClassDescriptor): Set<KotlinTarget>? {
|
||||||
val targetEntryDescriptor = classDescriptor.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.target)
|
val targetEntryDescriptor = classDescriptor.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.target)
|
||||||
?: return null
|
?: return null
|
||||||
val valueArguments = targetEntryDescriptor.allValueArguments
|
val valueArguments = targetEntryDescriptor.allValueArguments
|
||||||
val valueArgument = valueArguments.entries.firstOrNull()?.value as? ArrayValue ?: return null
|
val valueArgument = valueArguments.entries.firstOrNull()?.value as? ArrayValue ?: return null
|
||||||
return valueArgument.value.filterIsInstance<EnumValue>().mapNotNull {
|
return valueArgument.value.filterIsInstance<EnumValue>().mapNotNull {
|
||||||
@@ -211,8 +217,8 @@ class AnnotationChecker(
|
|||||||
return getActualTargetList(annotated, descriptor, trace).defaultTargets
|
return getActualTargetList(annotated, descriptor, trace).defaultTargets
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DeclarationDescriptor?.hasBackingField(bindingTrace: BindingTrace)
|
private fun DeclarationDescriptor?.hasBackingField(bindingTrace: BindingTrace) =
|
||||||
= (this as? PropertyDescriptor)?.let { bindingTrace.get(BindingContext.BACKING_FIELD_REQUIRED, it) } ?: false
|
(this as? PropertyDescriptor)?.let { bindingTrace.get(BindingContext.BACKING_FIELD_REQUIRED, it) } ?: false
|
||||||
|
|
||||||
private fun getActualTargetList(annotated: KtElement, descriptor: DeclarationDescriptor?, trace: BindingTrace): TargetList {
|
private fun getActualTargetList(annotated: KtElement, descriptor: DeclarationDescriptor?, trace: BindingTrace): TargetList {
|
||||||
return when (annotated) {
|
return when (annotated) {
|
||||||
@@ -273,29 +279,32 @@ class AnnotationChecker(
|
|||||||
if (backingField) extraTargets(FIELD)
|
if (backingField) extraTargets(FIELD)
|
||||||
if (delegate) {
|
if (delegate) {
|
||||||
onlyWithUseSiteTarget(VALUE_PARAMETER, PROPERTY_GETTER, PROPERTY_SETTER, FIELD)
|
onlyWithUseSiteTarget(VALUE_PARAMETER, PROPERTY_GETTER, PROPERTY_SETTER, FIELD)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
onlyWithUseSiteTarget(VALUE_PARAMETER, PROPERTY_GETTER, PROPERTY_SETTER)
|
onlyWithUseSiteTarget(VALUE_PARAMETER, PROPERTY_GETTER, PROPERTY_SETTER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun T_MEMBER_PROPERTY(backingField: Boolean, delegate: Boolean) =
|
fun T_MEMBER_PROPERTY(backingField: Boolean, delegate: Boolean) =
|
||||||
targetList(when {
|
targetList(
|
||||||
|
when {
|
||||||
backingField -> MEMBER_PROPERTY_WITH_BACKING_FIELD
|
backingField -> MEMBER_PROPERTY_WITH_BACKING_FIELD
|
||||||
delegate -> MEMBER_PROPERTY_WITH_DELEGATE
|
delegate -> MEMBER_PROPERTY_WITH_DELEGATE
|
||||||
else -> MEMBER_PROPERTY_WITHOUT_FIELD_OR_DELEGATE
|
else -> MEMBER_PROPERTY_WITHOUT_FIELD_OR_DELEGATE
|
||||||
}, MEMBER_PROPERTY, PROPERTY) {
|
}, MEMBER_PROPERTY, PROPERTY
|
||||||
propertyTargets(backingField, delegate)
|
) {
|
||||||
}
|
propertyTargets(backingField, delegate)
|
||||||
|
}
|
||||||
|
|
||||||
fun T_TOP_LEVEL_PROPERTY(backingField: Boolean, delegate: Boolean) =
|
fun T_TOP_LEVEL_PROPERTY(backingField: Boolean, delegate: Boolean) =
|
||||||
targetList(when {
|
targetList(
|
||||||
|
when {
|
||||||
backingField -> TOP_LEVEL_PROPERTY_WITH_BACKING_FIELD
|
backingField -> TOP_LEVEL_PROPERTY_WITH_BACKING_FIELD
|
||||||
delegate -> TOP_LEVEL_PROPERTY_WITH_DELEGATE
|
delegate -> TOP_LEVEL_PROPERTY_WITH_DELEGATE
|
||||||
else -> TOP_LEVEL_PROPERTY_WITHOUT_FIELD_OR_DELEGATE
|
else -> TOP_LEVEL_PROPERTY_WITHOUT_FIELD_OR_DELEGATE
|
||||||
}, TOP_LEVEL_PROPERTY, PROPERTY) {
|
}, TOP_LEVEL_PROPERTY, PROPERTY
|
||||||
propertyTargets(backingField, delegate)
|
) {
|
||||||
}
|
propertyTargets(backingField, delegate)
|
||||||
|
}
|
||||||
|
|
||||||
val T_PROPERTY_GETTER = targetList(PROPERTY_GETTER)
|
val T_PROPERTY_GETTER = targetList(PROPERTY_GETTER)
|
||||||
val T_PROPERTY_SETTER = targetList(PROPERTY_SETTER)
|
val T_PROPERTY_SETTER = targetList(PROPERTY_SETTER)
|
||||||
@@ -368,17 +377,22 @@ class AnnotationChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class TargetList(
|
private class TargetList(
|
||||||
val defaultTargets: List<KotlinTarget>,
|
val defaultTargets: List<KotlinTarget>,
|
||||||
val canBeSubstituted: List<KotlinTarget> = emptyList(),
|
val canBeSubstituted: List<KotlinTarget> = emptyList(),
|
||||||
val onlyWithUseSiteTarget: List<KotlinTarget> = emptyList())
|
val onlyWithUseSiteTarget: List<KotlinTarget> = emptyList()
|
||||||
|
)
|
||||||
|
|
||||||
private object UseSiteTargetsList {
|
private object UseSiteTargetsList {
|
||||||
val T_CONSTRUCTOR_PARAMETER = listOf(AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER,
|
val T_CONSTRUCTOR_PARAMETER = listOf(
|
||||||
AnnotationUseSiteTarget.PROPERTY,
|
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER,
|
||||||
AnnotationUseSiteTarget.FIELD)
|
AnnotationUseSiteTarget.PROPERTY,
|
||||||
|
AnnotationUseSiteTarget.FIELD
|
||||||
|
)
|
||||||
|
|
||||||
val T_PROPERTY = listOf(AnnotationUseSiteTarget.PROPERTY,
|
val T_PROPERTY = listOf(
|
||||||
AnnotationUseSiteTarget.FIELD)
|
AnnotationUseSiteTarget.PROPERTY,
|
||||||
|
AnnotationUseSiteTarget.FIELD
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,23 +29,23 @@ import org.jetbrains.kotlin.types.KotlinType
|
|||||||
|
|
||||||
abstract class AnnotationResolver {
|
abstract class AnnotationResolver {
|
||||||
fun resolveAnnotationsWithoutArguments(
|
fun resolveAnnotationsWithoutArguments(
|
||||||
scope: LexicalScope,
|
scope: LexicalScope,
|
||||||
modifierList: KtModifierList?,
|
modifierList: KtModifierList?,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
): Annotations = resolveAnnotationsFromModifierList(scope, modifierList, trace, false)
|
): Annotations = resolveAnnotationsFromModifierList(scope, modifierList, trace, false)
|
||||||
|
|
||||||
fun resolveAnnotationsWithArguments(
|
fun resolveAnnotationsWithArguments(
|
||||||
scope: LexicalScope,
|
scope: LexicalScope,
|
||||||
modifierList: KtModifierList?,
|
modifierList: KtModifierList?,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
): Annotations = resolveAnnotationsFromModifierList(scope, modifierList, trace, true)
|
): Annotations = resolveAnnotationsFromModifierList(scope, modifierList, trace, true)
|
||||||
|
|
||||||
|
|
||||||
private fun resolveAnnotationsFromModifierList(
|
private fun resolveAnnotationsFromModifierList(
|
||||||
scope: LexicalScope,
|
scope: LexicalScope,
|
||||||
modifierList: KtModifierList?,
|
modifierList: KtModifierList?,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
shouldResolveArguments: Boolean
|
shouldResolveArguments: Boolean
|
||||||
): Annotations {
|
): Annotations {
|
||||||
if (modifierList == null) {
|
if (modifierList == null) {
|
||||||
return Annotations.EMPTY
|
return Annotations.EMPTY
|
||||||
@@ -55,36 +55,36 @@ abstract class AnnotationResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun resolveAnnotationsWithoutArguments(
|
fun resolveAnnotationsWithoutArguments(
|
||||||
scope: LexicalScope,
|
scope: LexicalScope,
|
||||||
annotationEntries: @JvmSuppressWildcards List<KtAnnotationEntry>,
|
annotationEntries: @JvmSuppressWildcards List<KtAnnotationEntry>,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
): Annotations = resolveAnnotationEntries(scope, annotationEntries, trace, false)
|
): Annotations = resolveAnnotationEntries(scope, annotationEntries, trace, false)
|
||||||
|
|
||||||
fun resolveAnnotationsWithArguments(
|
fun resolveAnnotationsWithArguments(
|
||||||
scope: LexicalScope,
|
scope: LexicalScope,
|
||||||
annotationEntries: @JvmSuppressWildcards List<KtAnnotationEntry>,
|
annotationEntries: @JvmSuppressWildcards List<KtAnnotationEntry>,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
): Annotations = resolveAnnotationEntries(scope, annotationEntries, trace, true)
|
): Annotations = resolveAnnotationEntries(scope, annotationEntries, trace, true)
|
||||||
|
|
||||||
protected abstract fun resolveAnnotationEntries(
|
protected abstract fun resolveAnnotationEntries(
|
||||||
scope: LexicalScope,
|
scope: LexicalScope,
|
||||||
annotationEntries: @JvmSuppressWildcards List<KtAnnotationEntry>,
|
annotationEntries: @JvmSuppressWildcards List<KtAnnotationEntry>,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
shouldResolveArguments: Boolean
|
shouldResolveArguments: Boolean
|
||||||
): Annotations
|
): Annotations
|
||||||
|
|
||||||
|
|
||||||
abstract fun resolveAnnotationType(scope: LexicalScope, entryElement: KtAnnotationEntry, trace: BindingTrace): KotlinType
|
abstract fun resolveAnnotationType(scope: LexicalScope, entryElement: KtAnnotationEntry, trace: BindingTrace): KotlinType
|
||||||
|
|
||||||
abstract fun resolveAnnotationCall(
|
abstract fun resolveAnnotationCall(
|
||||||
annotationEntry: KtAnnotationEntry,
|
annotationEntry: KtAnnotationEntry,
|
||||||
scope: LexicalScope,
|
scope: LexicalScope,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
): OverloadResolutionResults<FunctionDescriptor>
|
): OverloadResolutionResults<FunctionDescriptor>
|
||||||
|
|
||||||
abstract fun getAnnotationArgumentValue(
|
abstract fun getAnnotationArgumentValue(
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
valueParameter: ValueParameterDescriptor,
|
valueParameter: ValueParameterDescriptor,
|
||||||
resolvedArgument: ResolvedValueArgument
|
resolvedArgument: ResolvedValueArgument
|
||||||
): ConstantValue<*>?
|
): ConstantValue<*>?
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-8
@@ -46,26 +46,26 @@ object AnnotationUseSiteTargetChecker {
|
|||||||
when (target) {
|
when (target) {
|
||||||
AnnotationUseSiteTarget.FIELD -> checkIfHasBackingField(annotated, descriptor, annotation)
|
AnnotationUseSiteTarget.FIELD -> checkIfHasBackingField(annotated, descriptor, annotation)
|
||||||
AnnotationUseSiteTarget.PROPERTY,
|
AnnotationUseSiteTarget.PROPERTY,
|
||||||
AnnotationUseSiteTarget.PROPERTY_GETTER -> {}
|
AnnotationUseSiteTarget.PROPERTY_GETTER -> {
|
||||||
|
}
|
||||||
AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD -> checkIfDelegatedProperty(annotated, annotation)
|
AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD -> checkIfDelegatedProperty(annotated, annotation)
|
||||||
AnnotationUseSiteTarget.PROPERTY_SETTER -> checkIfMutableProperty(annotated, annotation)
|
AnnotationUseSiteTarget.PROPERTY_SETTER -> checkIfMutableProperty(annotated, annotation)
|
||||||
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> {
|
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> {
|
||||||
if (annotated !is KtParameter) {
|
if (annotated !is KtParameter) {
|
||||||
report(INAPPLICABLE_PARAM_TARGET.on(annotation))
|
report(INAPPLICABLE_PARAM_TARGET.on(annotation))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val containingDeclaration = bindingContext[BindingContext.VALUE_PARAMETER, annotated]?.containingDeclaration
|
val containingDeclaration = bindingContext[BindingContext.VALUE_PARAMETER, annotated]?.containingDeclaration
|
||||||
if (containingDeclaration !is ConstructorDescriptor || !containingDeclaration.isPrimary) {
|
if (containingDeclaration !is ConstructorDescriptor || !containingDeclaration.isPrimary) {
|
||||||
report(INAPPLICABLE_PARAM_TARGET.on(annotation))
|
report(INAPPLICABLE_PARAM_TARGET.on(annotation))
|
||||||
}
|
} else if (!annotated.hasValOrVar()) {
|
||||||
else if (!annotated.hasValOrVar()) {
|
|
||||||
report(REDUNDANT_ANNOTATION_TARGET.on(annotation, target.renderName))
|
report(REDUNDANT_ANNOTATION_TARGET.on(annotation, target.renderName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AnnotationUseSiteTarget.SETTER_PARAMETER -> checkIfMutableProperty(annotated, annotation)
|
AnnotationUseSiteTarget.SETTER_PARAMETER -> checkIfMutableProperty(annotated, annotation)
|
||||||
AnnotationUseSiteTarget.FILE -> reportDiagnosticOnce(INAPPLICABLE_FILE_TARGET.on(useSiteTarget))
|
AnnotationUseSiteTarget.FILE -> reportDiagnosticOnce(INAPPLICABLE_FILE_TARGET.on(useSiteTarget))
|
||||||
AnnotationUseSiteTarget.RECEIVER -> {}
|
AnnotationUseSiteTarget.RECEIVER -> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,11 @@ object AnnotationUseSiteTargetChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun BindingTrace.checkIfHasBackingField(annotated: KtAnnotated, descriptor: DeclarationDescriptor, annotation: KtAnnotationEntry) {
|
private fun BindingTrace.checkIfHasBackingField(
|
||||||
|
annotated: KtAnnotated,
|
||||||
|
descriptor: DeclarationDescriptor,
|
||||||
|
annotation: KtAnnotationEntry
|
||||||
|
) {
|
||||||
if (annotated is KtProperty && annotated.hasDelegate() &&
|
if (annotated is KtProperty && annotated.hasDelegate() &&
|
||||||
descriptor is PropertyDescriptor && get(BindingContext.BACKING_FIELD_REQUIRED, descriptor) != true) {
|
descriptor is PropertyDescriptor && get(BindingContext.BACKING_FIELD_REQUIRED, descriptor) != true) {
|
||||||
report(INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD.on(annotation))
|
report(INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD.on(annotation))
|
||||||
@@ -84,7 +88,7 @@ object AnnotationUseSiteTargetChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun KtAnnotationEntry.useSiteDescription() =
|
private fun KtAnnotationEntry.useSiteDescription() =
|
||||||
useSiteTarget?.getAnnotationUseSiteTarget()?.renderName ?: "unknown target" // should not happen
|
useSiteTarget?.getAnnotationUseSiteTarget()?.renderName ?: "unknown target" // should not happen
|
||||||
|
|
||||||
private fun BindingTrace.checkIfMutableProperty(annotated: KtAnnotated, annotation: KtAnnotationEntry) {
|
private fun BindingTrace.checkIfMutableProperty(annotated: KtAnnotated, annotation: KtAnnotationEntry) {
|
||||||
if (!checkIfProperty(annotated, annotation)) return
|
if (!checkIfProperty(annotated, annotation)) return
|
||||||
|
|||||||
@@ -36,12 +36,12 @@ private val JVM_SYNTHETIC_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmSynthetic")
|
|||||||
fun DeclarationDescriptor.hasJvmSyntheticAnnotation() = findJvmSyntheticAnnotation() != null
|
fun DeclarationDescriptor.hasJvmSyntheticAnnotation() = findJvmSyntheticAnnotation() != null
|
||||||
|
|
||||||
fun DeclarationDescriptor.findJvmSyntheticAnnotation() =
|
fun DeclarationDescriptor.findJvmSyntheticAnnotation() =
|
||||||
DescriptorUtils.getAnnotationByFqName(annotations, JVM_SYNTHETIC_ANNOTATION_FQ_NAME)
|
DescriptorUtils.getAnnotationByFqName(annotations, JVM_SYNTHETIC_ANNOTATION_FQ_NAME)
|
||||||
|
|
||||||
private val STRICTFP_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.Strictfp")
|
private val STRICTFP_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.Strictfp")
|
||||||
|
|
||||||
fun DeclarationDescriptor.findStrictfpAnnotation() =
|
fun DeclarationDescriptor.findStrictfpAnnotation() =
|
||||||
DescriptorUtils.getAnnotationByFqName(annotations, STRICTFP_ANNOTATION_FQ_NAME)
|
DescriptorUtils.getAnnotationByFqName(annotations, STRICTFP_ANNOTATION_FQ_NAME)
|
||||||
|
|
||||||
fun AnnotationDescriptor.argumentValue(parameterName: String): Any? {
|
fun AnnotationDescriptor.argumentValue(parameterName: String): Any? {
|
||||||
return allValueArguments[Name.identifier(parameterName)].takeUnless { it is ErrorValue }?.value
|
return allValueArguments[Name.identifier(parameterName)].takeUnless { it is ErrorValue }?.value
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ fun KtReturnExpression.getTargetFunctionDescriptor(context: BindingContext): Fun
|
|||||||
if (containingFunctionDescriptor == null) return null
|
if (containingFunctionDescriptor == null) return null
|
||||||
|
|
||||||
return generateSequence(containingFunctionDescriptor) { DescriptorUtils.getParentOfType(it, FunctionDescriptor::class.java) }
|
return generateSequence(containingFunctionDescriptor) { DescriptorUtils.getParentOfType(it, FunctionDescriptor::class.java) }
|
||||||
.dropWhile { it is AnonymousFunctionDescriptor }
|
.dropWhile { it is AnonymousFunctionDescriptor }
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KtReturnExpression.getTargetFunction(context: BindingContext): KtCallableDeclaration? {
|
fun KtReturnExpression.getTargetFunction(context: BindingContext): KtCallableDeclaration? {
|
||||||
@@ -65,8 +65,7 @@ fun <C : ResolutionContext<C>> ResolutionContext<C>.recordDataFlowInfo(expressio
|
|||||||
val typeInfo = trace.get(BindingContext.EXPRESSION_TYPE_INFO, expression)
|
val typeInfo = trace.get(BindingContext.EXPRESSION_TYPE_INFO, expression)
|
||||||
if (typeInfo != null) {
|
if (typeInfo != null) {
|
||||||
trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, typeInfo.replaceDataFlowInfo(dataFlowInfo))
|
trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, typeInfo.replaceDataFlowInfo(dataFlowInfo))
|
||||||
}
|
} else if (dataFlowInfo != DataFlowInfo.EMPTY) {
|
||||||
else if (dataFlowInfo != DataFlowInfo.EMPTY) {
|
|
||||||
// Don't store anything in BindingTrace if it's simply an empty DataFlowInfo
|
// Don't store anything in BindingTrace if it's simply an empty DataFlowInfo
|
||||||
trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, noTypeInfo(dataFlowInfo))
|
trace.record(BindingContext.EXPRESSION_TYPE_INFO, expression, noTypeInfo(dataFlowInfo))
|
||||||
}
|
}
|
||||||
@@ -93,8 +92,8 @@ fun BindingContext.getDataFlowInfoAfter(position: PsiElement): DataFlowInfo {
|
|||||||
fun BindingContext.getDataFlowInfoBefore(position: PsiElement): DataFlowInfo {
|
fun BindingContext.getDataFlowInfoBefore(position: PsiElement): DataFlowInfo {
|
||||||
for (element in position.parentsWithSelf) {
|
for (element in position.parentsWithSelf) {
|
||||||
(element as? KtExpression)
|
(element as? KtExpression)
|
||||||
?.let { this[BindingContext.DATA_FLOW_INFO_BEFORE, it] }
|
?.let { this[BindingContext.DATA_FLOW_INFO_BEFORE, it] }
|
||||||
?.let { return it }
|
?.let { return it }
|
||||||
}
|
}
|
||||||
return DataFlowInfo.EMPTY
|
return DataFlowInfo.EMPTY
|
||||||
}
|
}
|
||||||
@@ -107,7 +106,7 @@ fun KtExpression.getReferenceTargets(context: BindingContext): Collection<Declar
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun KtTypeReference.getAbbreviatedTypeOrType(context: BindingContext) =
|
fun KtTypeReference.getAbbreviatedTypeOrType(context: BindingContext) =
|
||||||
context[BindingContext.ABBREVIATED_TYPE, this] ?: context[BindingContext.TYPE, this]
|
context[BindingContext.ABBREVIATED_TYPE, this] ?: context[BindingContext.TYPE, this]
|
||||||
|
|
||||||
fun KtTypeElement.getAbbreviatedTypeOrType(context: BindingContext): KotlinType? {
|
fun KtTypeElement.getAbbreviatedTypeOrType(context: BindingContext): KotlinType? {
|
||||||
val parent = parent
|
val parent = parent
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.resolve
|
package org.jetbrains.kotlin.resolve
|
||||||
|
|
||||||
class BindingTraceFilter(val ignoreDiagnostics: Boolean) {
|
class BindingTraceFilter(val ignoreDiagnostics: Boolean) {
|
||||||
companion object {
|
companion object {
|
||||||
val ACCEPT_ALL = BindingTraceFilter(false)
|
val ACCEPT_ALL = BindingTraceFilter(false)
|
||||||
val NO_DIAGNOSTICS = BindingTraceFilter(true)
|
val NO_DIAGNOSTICS = BindingTraceFilter(true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ interface CodeAnalyzerInitializer {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getInstance(project: Project): CodeAnalyzerInitializer =
|
fun getInstance(project: Project): CodeAnalyzerInitializer =
|
||||||
ServiceManager.getService<CodeAnalyzerInitializer>(project, CodeAnalyzerInitializer::class.java)!!
|
ServiceManager.getService<CodeAnalyzerInitializer>(project, CodeAnalyzerInitializer::class.java)!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DummyCodeAnalyzerInitializer: CodeAnalyzerInitializer {
|
class DummyCodeAnalyzerInitializer : CodeAnalyzerInitializer {
|
||||||
override fun initialize(trace: BindingTrace, module: ModuleDescriptor, codeAnalyzer: KotlinCodeAnalyzer) {
|
override fun initialize(trace: BindingTrace, module: ModuleDescriptor, codeAnalyzer: KotlinCodeAnalyzer) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,25 +39,29 @@ import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
|
|||||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
|
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
|
||||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
|
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
|
||||||
|
|
||||||
class CollectionLiteralResolver(val module: ModuleDescriptor, val callResolver: CallResolver, val languageVersionSettings: LanguageVersionSettings) {
|
class CollectionLiteralResolver(
|
||||||
|
val module: ModuleDescriptor,
|
||||||
|
val callResolver: CallResolver,
|
||||||
|
val languageVersionSettings: LanguageVersionSettings
|
||||||
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
val PRIMITIVE_TYPE_TO_ARRAY: Map<PrimitiveType, Name> = hashMapOf(
|
val PRIMITIVE_TYPE_TO_ARRAY: Map<PrimitiveType, Name> = hashMapOf(
|
||||||
PrimitiveType.BOOLEAN to Name.identifier("booleanArrayOf"),
|
PrimitiveType.BOOLEAN to Name.identifier("booleanArrayOf"),
|
||||||
PrimitiveType.CHAR to Name.identifier("charArrayOf"),
|
PrimitiveType.CHAR to Name.identifier("charArrayOf"),
|
||||||
PrimitiveType.INT to Name.identifier("intArrayOf"),
|
PrimitiveType.INT to Name.identifier("intArrayOf"),
|
||||||
PrimitiveType.BYTE to Name.identifier("byteArrayOf"),
|
PrimitiveType.BYTE to Name.identifier("byteArrayOf"),
|
||||||
PrimitiveType.SHORT to Name.identifier("shortArrayOf"),
|
PrimitiveType.SHORT to Name.identifier("shortArrayOf"),
|
||||||
PrimitiveType.FLOAT to Name.identifier("floatArrayOf"),
|
PrimitiveType.FLOAT to Name.identifier("floatArrayOf"),
|
||||||
PrimitiveType.LONG to Name.identifier("longArrayOf"),
|
PrimitiveType.LONG to Name.identifier("longArrayOf"),
|
||||||
PrimitiveType.DOUBLE to Name.identifier("doubleArrayOf")
|
PrimitiveType.DOUBLE to Name.identifier("doubleArrayOf")
|
||||||
)
|
)
|
||||||
|
|
||||||
val ARRAY_OF_FUNCTION = Name.identifier("arrayOf")
|
val ARRAY_OF_FUNCTION = Name.identifier("arrayOf")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resolveCollectionLiteral(
|
fun resolveCollectionLiteral(
|
||||||
collectionLiteralExpression: KtCollectionLiteralExpression,
|
collectionLiteralExpression: KtCollectionLiteralExpression,
|
||||||
context: ExpressionTypingContext
|
context: ExpressionTypingContext
|
||||||
): KotlinTypeInfo {
|
): KotlinTypeInfo {
|
||||||
if (!isInsideAnnotationEntryOrClass(collectionLiteralExpression)) {
|
if (!isInsideAnnotationEntryOrClass(collectionLiteralExpression)) {
|
||||||
context.trace.report(UNSUPPORTED.on(collectionLiteralExpression, "Collection literals outside of annotations"))
|
context.trace.report(UNSUPPORTED.on(collectionLiteralExpression, "Collection literals outside of annotations"))
|
||||||
@@ -69,15 +73,18 @@ class CollectionLiteralResolver(val module: ModuleDescriptor, val callResolver:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveCollectionLiteralSpecialMethod(
|
private fun resolveCollectionLiteralSpecialMethod(
|
||||||
expression: KtCollectionLiteralExpression,
|
expression: KtCollectionLiteralExpression,
|
||||||
context: ExpressionTypingContext
|
context: ExpressionTypingContext
|
||||||
): KotlinTypeInfo {
|
): KotlinTypeInfo {
|
||||||
val call = CallMaker.makeCallForCollectionLiteral(expression)
|
val call = CallMaker.makeCallForCollectionLiteral(expression)
|
||||||
val callName = getArrayFunctionCallName(context.expectedType)
|
val callName = getArrayFunctionCallName(context.expectedType)
|
||||||
val functionDescriptors = getFunctionDescriptorForCollectionLiteral(expression, callName)
|
val functionDescriptors = getFunctionDescriptorForCollectionLiteral(expression, callName)
|
||||||
if (functionDescriptors.isEmpty()) {
|
if (functionDescriptors.isEmpty()) {
|
||||||
context.trace.report(MISSING_STDLIB.on(
|
context.trace.report(
|
||||||
expression, "Collection literal call '$callName()' is unresolved"))
|
MISSING_STDLIB.on(
|
||||||
|
expression, "Collection literal call '$callName()' is unresolved"
|
||||||
|
)
|
||||||
|
)
|
||||||
return noTypeInfo(context)
|
return noTypeInfo(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,8 +99,8 @@ class CollectionLiteralResolver(val module: ModuleDescriptor, val callResolver:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getFunctionDescriptorForCollectionLiteral(
|
private fun getFunctionDescriptorForCollectionLiteral(
|
||||||
expression: KtCollectionLiteralExpression,
|
expression: KtCollectionLiteralExpression,
|
||||||
callName: Name
|
callName: Name
|
||||||
): Collection<SimpleFunctionDescriptor> {
|
): Collection<SimpleFunctionDescriptor> {
|
||||||
val memberScopeOfKotlinPackage = module.getPackage(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME).memberScope
|
val memberScopeOfKotlinPackage = module.getPackage(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME).memberScope
|
||||||
return memberScopeOfKotlinPackage.getContributedFunctions(callName, KotlinLookupLocation(expression))
|
return memberScopeOfKotlinPackage.getContributedFunctions(callName, KotlinLookupLocation(expression))
|
||||||
|
|||||||
+8
-8
@@ -23,18 +23,18 @@ import org.jetbrains.kotlin.types.WrappedTypeFactory
|
|||||||
|
|
||||||
interface DeclarationReturnTypeSanitizer {
|
interface DeclarationReturnTypeSanitizer {
|
||||||
fun sanitizeReturnType(
|
fun sanitizeReturnType(
|
||||||
inferred: UnwrappedType,
|
inferred: UnwrappedType,
|
||||||
wrappedTypeFactory: WrappedTypeFactory,
|
wrappedTypeFactory: WrappedTypeFactory,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
): UnwrappedType
|
): UnwrappedType
|
||||||
|
|
||||||
object Default : DeclarationReturnTypeSanitizer {
|
object Default : DeclarationReturnTypeSanitizer {
|
||||||
override fun sanitizeReturnType(
|
override fun sanitizeReturnType(
|
||||||
inferred: UnwrappedType,
|
inferred: UnwrappedType,
|
||||||
wrappedTypeFactory: WrappedTypeFactory,
|
wrappedTypeFactory: WrappedTypeFactory,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
) = inferred
|
) = inferred
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user