ControlFlowInformationProvider: fix warnings

This commit is contained in:
Mikhail Glukhikh
2019-07-09 17:24:25 +03:00
parent 5e94f537ef
commit b97f187cf6
@@ -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