Reformat 'frontend' module according to new codestyle

This commit is contained in:
Dmitry Savvinov
2018-01-16 10:57:56 +03:00
parent b567817d1f
commit e5f0ffb0c2
204 changed files with 3869 additions and 3395 deletions
@@ -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)
}
}
@@ -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")
}
@@ -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
@@ -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)
@@ -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) {
@@ -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(), " ") ?: ""
}
@@ -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>
}
@@ -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)
}
@@ -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)
}
@@ -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)
}
@@ -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)
}
@@ -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)
}
@@ -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
}
@@ -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)
}
@@ -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)
}
@@ -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)
@@ -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)
}
@@ -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) {
@@ -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)
}
@@ -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)
}
@@ -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)
}
@@ -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) {
@@ -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()
@@ -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? {
@@ -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)
}
@@ -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
@@ -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)
@@ -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
)
}
}
@@ -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)
@@ -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(")")
}
}
@@ -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 ->
{
@@ -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
@@ -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
}
@@ -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
)
}
@@ -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?
@@ -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 }
}
@@ -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
@@ -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 {
@@ -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? {
@@ -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
@@ -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)
}
@@ -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)
@@ -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()
@@ -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
}
@@ -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<*>?
}
@@ -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))
@@ -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