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