ControlFlowInformationProvider: fix warnings
This commit is contained in:
@@ -218,7 +218,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
val element = localDeclarationInstruction.element
|
val element = localDeclarationInstruction.element
|
||||||
if (element is KtDeclarationWithBody) {
|
if (element is KtDeclarationWithBody) {
|
||||||
|
|
||||||
val functionDescriptor = trace.bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element) as? CallableDescriptor
|
val functionDescriptor = trace.bindingContext.get(DECLARATION_TO_DESCRIPTOR, element) as? CallableDescriptor
|
||||||
val expectedType = functionDescriptor?.returnType
|
val expectedType = functionDescriptor?.returnType
|
||||||
|
|
||||||
val providerForLocalDeclaration = ControlFlowInformationProvider(
|
val providerForLocalDeclaration = ControlFlowInformationProvider(
|
||||||
@@ -440,7 +440,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
is KtDeclarationWithBody -> {
|
is KtDeclarationWithBody -> {
|
||||||
// If it is captured write in lambda that is called in-place, then skip it (treat as parent)
|
// If it is captured write in lambda that is called in-place, then skip it (treat as parent)
|
||||||
val maybeEnclosingLambdaExpr = parentDeclaration.parent
|
val maybeEnclosingLambdaExpr = parentDeclaration.parent
|
||||||
if (maybeEnclosingLambdaExpr is KtLambdaExpression && trace[BindingContext.LAMBDA_INVOCATIONS, maybeEnclosingLambdaExpr] != null) {
|
if (maybeEnclosingLambdaExpr is KtLambdaExpression && trace[LAMBDA_INVOCATIONS, maybeEnclosingLambdaExpr] != null) {
|
||||||
parentDeclaration = getElementParentDeclaration(parentDeclaration)
|
parentDeclaration = getElementParentDeclaration(parentDeclaration)
|
||||||
continue@loop
|
continue@loop
|
||||||
}
|
}
|
||||||
@@ -466,7 +466,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
val variableDescriptor = ctxt.variableDescriptor
|
val variableDescriptor = ctxt.variableDescriptor
|
||||||
val mayBeInitializedNotHere = ctxt.enterInitState?.mayBeInitialized() ?: false
|
val mayBeInitializedNotHere = ctxt.enterInitState?.mayBeInitialized() ?: false
|
||||||
val hasBackingField = (variableDescriptor as? PropertyDescriptor)?.let {
|
val hasBackingField = (variableDescriptor as? PropertyDescriptor)?.let {
|
||||||
trace.get(BindingContext.BACKING_FIELD_REQUIRED, it)
|
trace.get(BACKING_FIELD_REQUIRED, it)
|
||||||
} ?: true
|
} ?: true
|
||||||
if (variableDescriptor is PropertyDescriptor && variableDescriptor.isVar) {
|
if (variableDescriptor is PropertyDescriptor && variableDescriptor.isVar) {
|
||||||
val descriptor = BindingContextUtils.getEnclosingDescriptor(trace.bindingContext, expression)
|
val descriptor = BindingContextUtils.getEnclosingDescriptor(trace.bindingContext, expression)
|
||||||
@@ -493,15 +493,14 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
variableDescriptor != null && !variableDescriptor.isVar
|
variableDescriptor != null && !variableDescriptor.isVar
|
||||||
) {
|
) {
|
||||||
var hasReassignMethodReturningUnit = false
|
var hasReassignMethodReturningUnit = false
|
||||||
val parent = expression.parent
|
|
||||||
val operationReference =
|
val operationReference =
|
||||||
when (parent) {
|
when (val parent = expression.parent) {
|
||||||
is KtBinaryExpression -> parent.operationReference
|
is KtBinaryExpression -> parent.operationReference
|
||||||
is KtUnaryExpression -> parent.operationReference
|
is KtUnaryExpression -> parent.operationReference
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
if (operationReference != null) {
|
if (operationReference != null) {
|
||||||
val descriptor = trace.get(BindingContext.REFERENCE_TARGET, operationReference)
|
val descriptor = trace.get(REFERENCE_TARGET, operationReference)
|
||||||
if (descriptor is FunctionDescriptor) {
|
if (descriptor is FunctionDescriptor) {
|
||||||
if (descriptor.returnType?.let { KotlinBuiltIns.isUnit(it) } == true) {
|
if (descriptor.returnType?.let { KotlinBuiltIns.isUnit(it) } == true) {
|
||||||
hasReassignMethodReturningUnit = true
|
hasReassignMethodReturningUnit = true
|
||||||
@@ -545,9 +544,9 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
|
|
||||||
private fun reportValReassigned(expression: KtExpression, variableDescriptor: VariableDescriptor, ctxt: VariableInitContext) {
|
private fun reportValReassigned(expression: KtExpression, variableDescriptor: VariableDescriptor, ctxt: VariableInitContext) {
|
||||||
val diagnosticFactory = if (languageVersionSettings.supportsFeature(LanguageFeature.RestrictionOfValReassignmentViaBackingField))
|
val diagnosticFactory = if (languageVersionSettings.supportsFeature(LanguageFeature.RestrictionOfValReassignmentViaBackingField))
|
||||||
Errors.VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR
|
VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR
|
||||||
else
|
else
|
||||||
Errors.VAL_REASSIGNMENT_VIA_BACKING_FIELD
|
VAL_REASSIGNMENT_VIA_BACKING_FIELD
|
||||||
|
|
||||||
report(diagnosticFactory.on(expression, variableDescriptor), ctxt)
|
report(diagnosticFactory.on(expression, variableDescriptor), ctxt)
|
||||||
}
|
}
|
||||||
@@ -563,7 +562,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun VariableInitContext.isInitializationBeforeDeclaration(): Boolean =
|
private fun VariableInitContext.isInitializationBeforeDeclaration(): Boolean =
|
||||||
// is not declared
|
// is not declared
|
||||||
enterInitState?.isDeclared != true && exitInitState?.isDeclared != true &&
|
enterInitState?.isDeclared != true && exitInitState?.isDeclared != true &&
|
||||||
// wasn't initialized before current instruction
|
// wasn't initialized before current instruction
|
||||||
enterInitState?.mayBeInitialized() != true
|
enterInitState?.mayBeInitialized() != true
|
||||||
@@ -574,7 +573,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
|| ctxt.enterInitState?.mayBeInitialized() == true
|
|| ctxt.enterInitState?.mayBeInitialized() == true
|
||||||
|| ctxt.exitInitState?.mayBeInitialized() != true
|
|| ctxt.exitInitState?.mayBeInitialized() != true
|
||||||
|| !variableDescriptor.isVar
|
|| !variableDescriptor.isVar
|
||||||
|| trace.get(BindingContext.BACKING_FIELD_REQUIRED, variableDescriptor) != true
|
|| trace.get(BACKING_FIELD_REQUIRED, variableDescriptor) != true
|
||||||
) {
|
) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -609,7 +608,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
for (variable in declaredVariables) {
|
for (variable in declaredVariables) {
|
||||||
if (variable is PropertyDescriptor) {
|
if (variable is PropertyDescriptor) {
|
||||||
if (initializers.incoming.getOrNull(variable)?.definitelyInitialized() == true) continue
|
if (initializers.incoming.getOrNull(variable)?.definitelyInitialized() == true) continue
|
||||||
trace.record(BindingContext.IS_UNINITIALIZED, variable)
|
trace.record(IS_UNINITIALIZED, variable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -643,7 +642,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
if (trace.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null) return@traverse
|
if (trace.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null) return@traverse
|
||||||
val expressionInQuestion = instruction.element as? KtExpression ?: return@traverse
|
val expressionInQuestion = instruction.element as? KtExpression ?: return@traverse
|
||||||
if (variableUseState != READ) {
|
if (variableUseState != READ) {
|
||||||
unusedValueExpressions.put(expressionInQuestion, variableDescriptor to ctxt)
|
unusedValueExpressions[expressionInQuestion] = variableDescriptor to ctxt
|
||||||
} else {
|
} else {
|
||||||
usedValueExpressions.add(expressionInQuestion)
|
usedValueExpressions.add(expressionInQuestion)
|
||||||
}
|
}
|
||||||
@@ -715,8 +714,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
!diagnosticSuppressor.shouldReportUnusedParameter(variableDescriptor)
|
!diagnosticSuppressor.shouldReportUnusedParameter(variableDescriptor)
|
||||||
) return
|
) return
|
||||||
|
|
||||||
val owner = element.parent.parent
|
when (val owner = element.parent.parent) {
|
||||||
when (owner) {
|
|
||||||
is KtPrimaryConstructor -> if (!element.hasValOrVar()) {
|
is KtPrimaryConstructor -> if (!element.hasValOrVar()) {
|
||||||
val containingClass = (functionDescriptor as ConstructorDescriptor).containingDeclaration
|
val containingClass = (functionDescriptor as ConstructorDescriptor).containingDeclaration
|
||||||
if (!DescriptorUtils.isAnnotationClass(containingClass)) {
|
if (!DescriptorUtils.isAnnotationClass(containingClass)) {
|
||||||
@@ -793,11 +791,11 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
val value = (instruction as? InstructionWithValue)?.outputValue
|
val value = (instruction as? InstructionWithValue)?.outputValue
|
||||||
val pseudocode = instruction.owner
|
val pseudocode = instruction.owner
|
||||||
val usages = pseudocode.getUsages(value)
|
val usages = pseudocode.getUsages(value)
|
||||||
val isUsedAsExpression = !usages.isEmpty()
|
val isUsedAsExpression = usages.isNotEmpty()
|
||||||
val isUsedAsResultOfLambda = isUsedAsResultOfLambda(usages)
|
val isUsedAsResultOfLambda = isUsedAsResultOfLambda(usages)
|
||||||
for (element in pseudocode.getValueElements(value)) {
|
for (element in pseudocode.getValueElements(value)) {
|
||||||
trace.record(BindingContext.USED_AS_EXPRESSION, element, isUsedAsExpression)
|
trace.record(USED_AS_EXPRESSION, element, isUsedAsExpression)
|
||||||
trace.record(BindingContext.USED_AS_RESULT_OF_LAMBDA, element, isUsedAsResultOfLambda)
|
trace.record(USED_AS_RESULT_OF_LAMBDA, element, isUsedAsResultOfLambda)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -898,14 +896,14 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
val enumClassDescriptor = WhenChecker.getClassDescriptorOfTypeIfEnum(subjectType)
|
val enumClassDescriptor = WhenChecker.getClassDescriptorOfTypeIfEnum(subjectType)
|
||||||
if (enumClassDescriptor != null) {
|
if (enumClassDescriptor != null) {
|
||||||
val enumMissingCases = WhenChecker.getEnumMissingCases(element, context, enumClassDescriptor)
|
val enumMissingCases = WhenChecker.getEnumMissingCases(element, context, enumClassDescriptor)
|
||||||
if (!enumMissingCases.isEmpty()) {
|
if (enumMissingCases.isNotEmpty()) {
|
||||||
trace.report(NON_EXHAUSTIVE_WHEN.on(element, enumMissingCases))
|
trace.report(NON_EXHAUSTIVE_WHEN.on(element, enumMissingCases))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val sealedClassDescriptor = WhenChecker.getClassDescriptorOfTypeIfSealed(subjectType)
|
val sealedClassDescriptor = WhenChecker.getClassDescriptorOfTypeIfSealed(subjectType)
|
||||||
if (sealedClassDescriptor != null) {
|
if (sealedClassDescriptor != null) {
|
||||||
val sealedMissingCases = WhenChecker.getSealedMissingCases(element, context, sealedClassDescriptor)
|
val sealedMissingCases = WhenChecker.getSealedMissingCases(element, context, sealedClassDescriptor)
|
||||||
if (!sealedMissingCases.isEmpty()) {
|
if (sealedMissingCases.isNotEmpty()) {
|
||||||
trace.report(NON_EXHAUSTIVE_WHEN_ON_SEALED_CLASS.on(element, sealedMissingCases))
|
trace.report(NON_EXHAUSTIVE_WHEN_ON_SEALED_CLASS.on(element, sealedMissingCases))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -926,7 +924,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
// Tail calls
|
// Tail calls
|
||||||
|
|
||||||
private fun markAndCheckTailCalls() {
|
private fun markAndCheckTailCalls() {
|
||||||
val subroutineDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, subroutine) as? FunctionDescriptor ?: return
|
val subroutineDescriptor = trace.get(DECLARATION_TO_DESCRIPTOR, subroutine) as? FunctionDescriptor ?: return
|
||||||
|
|
||||||
markAndCheckRecursiveTailCalls(subroutineDescriptor)
|
markAndCheckRecursiveTailCalls(subroutineDescriptor)
|
||||||
}
|
}
|
||||||
@@ -936,7 +934,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
if (subroutine is KtNamedFunction && !subroutine.hasBody()) return
|
if (subroutine is KtNamedFunction && !subroutine.hasBody()) return
|
||||||
|
|
||||||
// finally blocks are copied which leads to multiple diagnostics reported on one instruction
|
// finally blocks are copied which leads to multiple diagnostics reported on one instruction
|
||||||
class KindAndCall(var kind: TailRecursionKind, internal val call: ResolvedCall<*>)
|
class KindAndCall(var kind: TailRecursionKind, val call: ResolvedCall<*>)
|
||||||
|
|
||||||
val calls = HashMap<KtElement, KindAndCall>()
|
val calls = HashMap<KtElement, KindAndCall>()
|
||||||
traverseCalls traverse@{ instruction, resolvedCall ->
|
traverseCalls traverse@{ instruction, resolvedCall ->
|
||||||
@@ -955,7 +953,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
if (isInsideTry(element)) {
|
if (isInsideTry(element)) {
|
||||||
// We do not support tail calls Collections.singletonMap() try-catch-finally, for simplicity of the mental model
|
// We do not support tail calls Collections.singletonMap() try-catch-finally, for simplicity of the mental model
|
||||||
// very few cases there would be real tail-calls, and it's often not so easy for the user to see why
|
// very few cases there would be real tail-calls, and it's often not so easy for the user to see why
|
||||||
calls.put(element, KindAndCall(IN_TRY, resolvedCall))
|
calls[element] = KindAndCall(IN_TRY, resolvedCall)
|
||||||
return@traverse
|
return@traverse
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -970,14 +968,14 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
val kind = if (sameDispatchReceiver && instruction.isTailCall()) TAIL_CALL else NON_TAIL
|
val kind = if (sameDispatchReceiver && instruction.isTailCall()) TAIL_CALL else NON_TAIL
|
||||||
|
|
||||||
val kindAndCall = calls[element]
|
val kindAndCall = calls[element]
|
||||||
calls.put(element, KindAndCall(combineKinds(kind, kindAndCall?.kind), resolvedCall))
|
calls[element] = KindAndCall(combineKinds(kind, kindAndCall?.kind), resolvedCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasTailCalls = false
|
var hasTailCalls = false
|
||||||
for ((element, kindAndCall) in calls) {
|
for ((element, kindAndCall) in calls) {
|
||||||
when (kindAndCall.kind) {
|
when (kindAndCall.kind) {
|
||||||
TAIL_CALL -> {
|
TAIL_CALL -> {
|
||||||
trace.record(TAIL_RECURSION_CALL, kindAndCall.call.call, TailRecursionKind.TAIL_CALL)
|
trace.record(TAIL_RECURSION_CALL, kindAndCall.call.call, TAIL_CALL)
|
||||||
hasTailCalls = true
|
hasTailCalls = true
|
||||||
}
|
}
|
||||||
IN_TRY -> trace.report(Errors.TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED.on(element))
|
IN_TRY -> trace.report(Errors.TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED.on(element))
|
||||||
@@ -1034,7 +1032,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
val previouslyReported = ctxt.reportedDiagnosticMap
|
val previouslyReported = ctxt.reportedDiagnosticMap
|
||||||
previouslyReported.put(instruction, diagnostic.factory)
|
previouslyReported[instruction] = diagnostic.factory
|
||||||
|
|
||||||
var alreadyReported = false
|
var alreadyReported = false
|
||||||
var sameErrorForAllCopies = true
|
var sameErrorForAllCopies = true
|
||||||
|
|||||||
Reference in New Issue
Block a user