@NotNull protected JetTypeInfo visitAssignment( JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) { ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(scope); JetExpression left = context.expressionTypingServices.deparenthesize(expression.getLeft(), context); JetExpression right = expression.getRight(); if (left instanceof JetArrayAccessExpression) { JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) left; if (right == null) return JetTypeInfo.create(null, context.dataFlowInfo); JetTypeInfo typeInfo = basic.resolveArrayAccessSetMethod(arrayAccessExpression, right, context, context.trace); basic.checkLValue(context.trace, arrayAccessExpression); return JetTypeInfo.create( checkAssignmentType(typeInfo.getType(), expression, contextWithExpectedType), typeInfo.getDataFlowInfo()); } JetTypeInfo leftInfo = facade.getTypeInfo(expression.getLeft(), context); JetType leftType = leftInfo.getType(); DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo(); if (right != null) { JetTypeInfo rightInfo = facade.getTypeInfo( right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType)); dataFlowInfo = rightInfo.getDataFlowInfo(); } if (leftType != null) { // if leftType == null, some another error has been generated basic.checkLValue(context.trace, expression.getLeft()); } return DataFlowUtils.checkStatementType(expression, contextWithExpectedType, dataFlowInfo); }
@Nullable public static BinaryCall getRangeAsBinaryCall(@NotNull JetForExpression forExpression) { // We are looking for rangeTo() calls // Other binary operations will succeed too, but will be filtered out later (by examining a // resolvedCall) JetExpression rangeExpression = forExpression.getLoopRange(); assert rangeExpression != null; JetExpression loopRange = JetPsiUtil.deparenthesizeWithNoTypeResolution(rangeExpression); if (loopRange instanceof JetQualifiedExpression) { // a.rangeTo(b) JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) loopRange; JetExpression selector = qualifiedExpression.getSelectorExpression(); if (selector instanceof JetCallExpression) { JetCallExpression callExpression = (JetCallExpression) selector; List<? extends ValueArgument> arguments = callExpression.getValueArguments(); if (arguments.size() == 1) { return new BinaryCall( qualifiedExpression.getReceiverExpression(), callExpression.getCalleeExpression(), arguments.get(0).getArgumentExpression()); } } } else if (loopRange instanceof JetBinaryExpression) { // a rangeTo b // a .. b JetBinaryExpression binaryExpression = (JetBinaryExpression) loopRange; return new BinaryCall( binaryExpression.getLeft(), binaryExpression.getOperationReference(), binaryExpression.getRight()); } return null; }
@SuppressWarnings("ConstantConditions") public static void foldWhenExpressionWithAssignments(JetWhenExpression whenExpression) { Project project = whenExpression.getProject(); assert !whenExpression.getEntries().isEmpty() : FOLD_WITHOUT_CHECK; JetBinaryExpression firstAssignment = getFoldableBranchedAssignment(whenExpression.getEntries().get(0).getExpression()); assertNotNull(firstAssignment); String op = firstAssignment.getOperationReference().getText(); JetSimpleNameExpression lhs = (JetSimpleNameExpression) firstAssignment.getLeft(); JetBinaryExpression assignment = JetPsiFactory.createBinaryExpression(project, lhs, op, whenExpression); JetWhenExpression newWhenExpression = (JetWhenExpression) assignment.getRight(); assertNotNull(newWhenExpression); for (JetWhenEntry entry : newWhenExpression.getEntries()) { JetBinaryExpression currAssignment = getFoldableBranchedAssignment(entry.getExpression()); assertNotNull(currAssignment); JetExpression currRhs = currAssignment.getRight(); assertNotNull(currRhs); currAssignment.replace(currRhs); } whenExpression.replace(assignment); }
@Override public boolean apply(@Nullable JetElement input) { if (input == null || !JetPsiUtil.isAssignment(input)) { return false; } JetBinaryExpression assignment = (JetBinaryExpression) input; if (assignment.getRight() == null || !(assignment.getLeft() instanceof JetSimpleNameExpression)) { return false; } if (assignment.getParent() instanceof JetBlockExpression) { //noinspection ConstantConditions return !JetPsiUtil.checkVariableDeclarationInBlock( (JetBlockExpression) assignment.getParent(), assignment.getLeft().getText()); } return true; }
private void checkPropertyDescriptor( @NotNull JetExpression expression, @NotNull PropertyDescriptor propertyDescriptor) { // Deprecated for Property if (reportAnnotationIfNeeded(expression, propertyDescriptor, propertyDescriptor.isVar())) { return; } // Deprecated for Getter (val, var), Setter (var) if (!propertyDescriptor.isVar()) { checkPropertyGetter(propertyDescriptor, expression); } else { IElementType operation = null; JetBinaryExpression binaryExpression = PsiTreeUtil.getParentOfType(expression, JetBinaryExpression.class); if (binaryExpression != null) { JetExpression left = binaryExpression.getLeft(); if (left == expression) { operation = binaryExpression.getOperationToken(); } else { JetReferenceExpression[] jetReferenceExpressions = PsiTreeUtil.getChildrenOfType(left, JetReferenceExpression.class); if (jetReferenceExpressions != null) { for (JetReferenceExpression expr : jetReferenceExpressions) { if (expr == expression) { operation = binaryExpression.getOperationToken(); break; } } } } } else { JetUnaryExpression unaryExpression = PsiTreeUtil.getParentOfType(expression, JetUnaryExpression.class); if (unaryExpression != null) { operation = unaryExpression.getOperationReference().getReferencedNameElementType(); } } if (operation != null && PROPERTY_SET_OPERATIONS.contains(operation)) { checkPropertySetter(propertyDescriptor, expression); } else { checkPropertyGetter(propertyDescriptor, expression); } } }
public static void foldIfExpressionWithAssignments(JetIfExpression ifExpression) { Project project = ifExpression.getProject(); JetBinaryExpression thenAssignment = getFoldableBranchedAssignment(ifExpression.getThen()); assertNotNull(thenAssignment); String op = thenAssignment.getOperationReference().getText(); JetSimpleNameExpression lhs = (JetSimpleNameExpression) thenAssignment.getLeft(); JetBinaryExpression assignment = JetPsiFactory.createBinaryExpression(project, lhs, op, ifExpression); JetIfExpression newIfExpression = (JetIfExpression) assignment.getRight(); assertNotNull(newIfExpression); //noinspection ConstantConditions thenAssignment = getFoldableBranchedAssignment(newIfExpression.getThen()); JetBinaryExpression elseAssignment = getFoldableBranchedAssignment(newIfExpression.getElse()); assertNotNull(thenAssignment); assertNotNull(elseAssignment); JetExpression thenRhs = thenAssignment.getRight(); JetExpression elseRhs = elseAssignment.getRight(); assertNotNull(thenRhs); assertNotNull(elseRhs); //noinspection ConstantConditions thenAssignment.replace(thenRhs); //noinspection ConstantConditions elseAssignment.replace(elseRhs); ifExpression.replace(assignment); }
@NotNull protected JetTypeInfo visitAssignmentOperation( JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) { // There is a temporary binding trace for an opportunity to resolve set method for array if // needed (the initial trace should be used there) TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create( contextWithExpectedType.trace, "trace to resolve array set method for binary expression", expression); ExpressionTypingContext context = contextWithExpectedType .replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE) .replaceBindingTrace(temporaryBindingTrace); JetSimpleNameExpression operationSign = expression.getOperationReference(); IElementType operationType = operationSign.getReferencedNameElementType(); JetTypeInfo leftInfo = facade.getTypeInfo(expression.getLeft(), context); JetType leftType = leftInfo.getType(); DataFlowInfo dataFlowInfo = leftInfo.getDataFlowInfo(); JetExpression right = expression.getRight(); JetExpression left = JetPsiUtil.deparenthesizeWithNoTypeResolution(expression.getLeft()); if (right == null || left == null) { temporaryBindingTrace.commit(); return JetTypeInfo.create(null, dataFlowInfo); } if (leftType == null) { dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); context.trace.report(UNRESOLVED_REFERENCE.on(operationSign)); temporaryBindingTrace.commit(); return JetTypeInfo.create(null, dataFlowInfo); } ExpressionReceiver receiver = new ExpressionReceiver(left, leftType); // We check that defined only one of '+=' and '+' operations, and call it (in the case '+' we // then also assign) // Check for '+=' Name name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType); TemporaryBindingTrace assignmentOperationTrace = TemporaryBindingTrace.create( context.trace, "trace to check assignment operation like '+=' for", expression); OverloadResolutionResults<FunctionDescriptor> assignmentOperationDescriptors = basic.getResolutionResultsForBinaryCall( scope, name, context.replaceBindingTrace(assignmentOperationTrace), expression, receiver); JetType assignmentOperationType = OverloadResolutionResultsUtil.getResultType(assignmentOperationDescriptors); // Check for '+' Name counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get( OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType)); TemporaryBindingTrace binaryOperationTrace = TemporaryBindingTrace.create( context.trace, "trace to check binary operation like '+' for", expression); OverloadResolutionResults<FunctionDescriptor> binaryOperationDescriptors = basic.getResolutionResultsForBinaryCall( scope, counterpartName, context.replaceBindingTrace(binaryOperationTrace), expression, receiver); JetType binaryOperationType = OverloadResolutionResultsUtil.getResultType(binaryOperationDescriptors); JetType type = assignmentOperationType != null ? assignmentOperationType : binaryOperationType; if (assignmentOperationType != null && binaryOperationType != null) { OverloadResolutionResults<FunctionDescriptor> ambiguityResolutionResults = OverloadResolutionResultsUtil.ambiguity( assignmentOperationDescriptors, binaryOperationDescriptors); context.trace.report( ASSIGN_OPERATOR_AMBIGUITY.on( operationSign, ambiguityResolutionResults.getResultingCalls())); Collection<DeclarationDescriptor> descriptors = Sets.newHashSet(); for (ResolvedCall<? extends FunctionDescriptor> call : ambiguityResolutionResults.getResultingCalls()) { descriptors.add(call.getResultingDescriptor()); } dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); context.trace.record(AMBIGUOUS_REFERENCE_TARGET, operationSign, descriptors); } else if (assignmentOperationType != null) { assignmentOperationTrace.commit(); if (!KotlinBuiltIns.getInstance().isUnit(assignmentOperationType)) { context.trace.report( ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT.on( operationSign, assignmentOperationDescriptors.getResultingDescriptor(), operationSign)); } } else { binaryOperationTrace.commit(); context.trace.record(VARIABLE_REASSIGNMENT, expression); if (left instanceof JetArrayAccessExpression) { ExpressionTypingContext contextForResolve = context .replaceScope(scope) .replaceBindingTrace( TemporaryBindingTrace.create( contextWithExpectedType.trace, "trace to resolve array set method for assignment", expression)); basic.resolveArrayAccessSetMethod( (JetArrayAccessExpression) left, right, contextForResolve, context.trace); } dataFlowInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo)).getDataFlowInfo(); } basic.checkLValue(context.trace, expression.getLeft()); temporaryBindingTrace.commit(); return JetTypeInfo.create( checkAssignmentType(type, expression, contextWithExpectedType), dataFlowInfo); }
private static boolean checkAssignmentsMatch(JetBinaryExpression a1, JetBinaryExpression a2) { return checkEquivalence(a1.getLeft(), a2.getLeft()) && a1.getOperationToken().equals(a2.getOperationToken()); }