@Override
      public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) {
        if (myWritten && myRead) {
          return;
        }
        super.visitReferenceExpression(expression);
        if (!expression.isReferenceTo(myVariable)) return;
        if (PsiUtil.isAccessedForWriting(expression)) {
          final PsiElement parent = PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class);
          if (parent instanceof PsiAssignmentExpression assignmentExpression) {
            final PsiExpression rhs = assignmentExpression.getRExpression();
            if (mayBeAccessedElsewhere(rhs)) {
              myWritten = true;
              myRead = true;
            }
            else if (!isZeroSizeArrayExpression(rhs)) {
              myWritten = true;
            }
            if (!ExpressionUtils.isVoidContext(assignmentExpression)) {
              myWritten = true;
              myRead = true;
            }
          }
          return;
        }
        myIsReferenced = true;
        PsiElement parent = getParent(expression);
        if (parent instanceof PsiArrayAccessExpression arrayAccessExpression) {
          parent = getParent(parent);
          while (parent instanceof PsiArrayAccessExpression &&
                 ((PsiArrayAccessExpression)parent).getArrayExpression() == arrayAccessExpression) {
            arrayAccessExpression = (PsiArrayAccessExpression)parent;
            parent = getParent(parent);
          }
          final PsiType type = arrayAccessExpression.getType();
          if (type != null) {
            final int dimensions = type.getArrayDimensions();
            if (dimensions > 0 && dimensions != myVariable.getType().getArrayDimensions()) {
              myWritten = true;
            }
          }
          if (PsiUtil.isAccessedForWriting(arrayAccessExpression)) {
            myWritten = true;
          }
          if (PsiUtil.isAccessedForReading(arrayAccessExpression) && !goesToSameArray(arrayAccessExpression) &&
              // compound writes like += are not considered as reads, because result result goes to the same array as well
              (!PsiUtil.isAccessedForWriting(arrayAccessExpression) || 
               parent instanceof PsiExpression && !ExpressionUtils.isVoidContext((PsiExpression)parent))) {
            myRead = true;
          }
        }
        else if (parent instanceof PsiReferenceExpression referenceExpression) {
          final String name = referenceExpression.getReferenceName();
          if ("clone".equals(name) && referenceExpression.getParent() instanceof PsiMethodCallExpression) {
            myRead = true;
          }
        }
        else if (parent instanceof PsiForeachStatement foreachStatement) {
          final PsiExpression iteratedValue = foreachStatement.getIteratedValue();
          if (PsiTreeUtil.isAncestor(iteratedValue, expression, false)) {
            myRead = true;
          }
        }
        else if (parent instanceof PsiExpressionList expressionList) {
          parent = parent.getParent();
          if (parent instanceof PsiMethodCallExpression methodCallExpression) {
            final PsiMethod method = methodCallExpression.resolveMethod();
            if (method != null) {
              final PsiClass aClass = method.getContainingClass();
              if (aClass != null) {
                final String methodName = method.getName();
                final String qualifiedName = aClass.getQualifiedName();
                if ("java.lang.System".equals(qualifiedName)) {
                  if ("arraycopy".equals(methodName)) {
                    final PsiExpression[] expressions = expressionList.getExpressions();
                    if (expressions.length == 5) {
                      if (PsiTreeUtil.isAncestor(expressions[0], expression, false)) {
                        myRead = true;
                        return;
                      }
                      else if (PsiTreeUtil.isAncestor(expressions[2], expression, false)) {
                        myWritten = true;
                        return;
                      }
                    }
                  }
                }
                else if (CommonClassNames.JAVA_UTIL_ARRAYS.equals(qualifiedName)) {
                  if (("fill".equals(methodName) || "parallelPrefix".equals(methodName) || "parallelSetAll".equals(methodName) ||
                      "parallelSort".equals(methodName) || "setAll".equals(methodName) || "sort".equals(methodName)) &&
                      PsiTreeUtil.isAncestor(expressionList.getExpressions()[0], expression, false)) {
                    myWritten = true;
                  }
                  else {
                    myRead = true;
                  }
                  return;
                }
              }
            }
          }
          myRead = true;
          myWritten = true;
        }
        else {
          myWritten = true;
          myRead = true;
        }
      }
@Override
      public void visitReferenceExpression(@NotNull PsiReferenceExpression expression)