public Description matchAssignment()

in nullaway/src/main/java/com/uber/nullaway/NullAway.java [501:565]


  public Description matchAssignment(AssignmentTree tree, VisitorState state) {
    if (!withinAnnotatedCode(state)) {
      return Description.NO_MATCH;
    }
    Type lhsType = ASTHelpers.getType(tree.getVariable());
    if (lhsType != null && lhsType.isPrimitive()) {
      doUnboxingCheck(state, tree.getExpression());
    }
    Symbol assigned = ASTHelpers.getSymbol(tree.getVariable());
    if (assigned instanceof Symbol.MethodSymbol) {
      // javac generates an AssignmentTree for setting an annotation attribute value.  E.g., for
      // `@SuppressWarnings("foo")`, javac generates an AssignmentTree of the form `value() =
      // "foo"`, where the LHS is a MethodSymbol.  We don't want to analyze these.
      return Description.NO_MATCH;
    }
    if (assigned != null && codeAnnotationInfo.isSymbolUnannotated(assigned, config, handler)) {
      // assigning to symbol that is unannotated
      return Description.NO_MATCH;
    }
    // generics check
    if (lhsType != null && config.isJSpecifyMode()) {
      genericsChecks.checkTypeParameterNullnessForAssignability(tree, this, state);
    }

    if (config.isJSpecifyMode() && tree.getVariable() instanceof ArrayAccessTree) {
      // check for a write of a @Nullable value into @NonNull array contents
      ArrayAccessTree arrayAccess = (ArrayAccessTree) tree.getVariable();
      ExpressionTree arrayExpr = arrayAccess.getExpression();
      ExpressionTree expression = tree.getExpression();
      Symbol arraySymbol = ASTHelpers.getSymbol(arrayExpr);
      if (arraySymbol != null) {
        boolean isElementNullable = isArrayElementNullable(arraySymbol, config);
        if (!isElementNullable && mayBeNullExpr(state, expression)) {
          String message = "Writing @Nullable expression into array with @NonNull contents.";
          ErrorMessage errorMessage =
              new ErrorMessage(MessageTypes.ASSIGN_NULLABLE_TO_NONNULL_ARRAY, message);
          return errorBuilder.createErrorDescription(
              errorMessage, buildDescription(tree), state, arraySymbol);
        }
      }
    }

    if (assigned == null || assigned.getKind() != ElementKind.FIELD) {
      // not a field of nullable type
      return Description.NO_MATCH;
    }

    if (Nullness.hasNullableAnnotation(assigned, config)
        || handler.onOverrideFieldNullability(assigned)) {
      // field already annotated
      return Description.NO_MATCH;
    }
    ExpressionTree expression = tree.getExpression();
    if (mayBeNullExpr(state, expression)) {
      String message = "assigning @Nullable expression to @NonNull field";
      return errorBuilder.createErrorDescriptionForNullAssignment(
          new ErrorMessage(MessageTypes.ASSIGN_FIELD_NULLABLE, message),
          expression,
          buildDescription(tree),
          state,
          ASTHelpers.getSymbol(tree.getVariable()));
    }
    handler.onNonNullFieldAssignment(assigned, getNullnessAnalysis(state), state);
    return Description.NO_MATCH;
  }