@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);
 }
Beispiel #2
0
 @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());
 }