org.jetbrains.kotlin.resolve.jvm.checkers.JvmArrayVariableInLoopAssignmentChecker.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.jvm.checkers
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
import org.jetbrains.kotlin.types.KotlinType
object JvmArrayVariableInLoopAssignmentChecker : AdditionalTypeChecker {
override fun checkType(
expression: KtExpression,
expressionType: KotlinType,
expressionTypeWithSmartCast: KotlinType,
c: ResolutionContext<*>
) {
if (c.languageVersionSettings.supportsFeature(LanguageFeature.ProperForInArrayLoopRangeVariableAssignmentSemantic)) return
val binaryExpression = expression as? KtBinaryExpression ?: return
if (binaryExpression.operationToken != KtTokens.EQ) return
val lhsExpression = binaryExpression.left as? KtSimpleNameExpression ?: return
val resolvedCall = lhsExpression.getResolvedCall(c.trace.bindingContext) ?: return
val variableDescriptor = resolvedCall.resultingDescriptor as? LocalVariableDescriptor ?: return
if (variableDescriptor is SyntheticFieldDescriptor) return
if (variableDescriptor.isDelegated) return
val variableType = variableDescriptor.returnType
if (!KotlinBuiltIns.isArrayOrPrimitiveArray(variableType)) return
if (!isOuterForLoopRangeVariable(expression, variableDescriptor, c)) return
val dataFlowValueKind = c.dataFlowValueFactory.createDataFlowValue(lhsExpression, variableType, c).kind
if (dataFlowValueKind != DataFlowValue.Kind.STABLE_VARIABLE) return
c.trace.report(ErrorsJvm.ASSIGNMENT_TO_ARRAY_LOOP_VARIABLE.on(lhsExpression))
}
private fun isOuterForLoopRangeVariable(
expression: KtExpression,
variableDescriptor: CallableDescriptor,
c: ResolutionContext<*>
): Boolean {
for (parent in expression.parents) {
if (parent is KtForExpression) {
val rangeExpression = parent.loopRange as? KtSimpleNameExpression ?: continue
val rangeResolvedCall = rangeExpression.getResolvedCall(c.trace.bindingContext) ?: continue
if (rangeResolvedCall.resultingDescriptor == variableDescriptor) {
return true
}
}
}
return false
}
}