docs: static String makeCheckDescription(ExpressionTree actual, VisitorState state) {
      /*
       * This conveniently also acts as a check that the actual and expected values aren't backward,
       * since the actual value is almost always an invocation on actual() and the expected value is
       * almost always a parameter.
       */
      if (actual.getKind() != METHOD_INVOCATION) {
        return null;
      }
  
      Deque<String> parts = new ArrayDeque<>();
      MethodInvocationTree invocation = (MethodInvocationTree) actual;
      while (true) {
        ExpressionTree methodSelect = invocation.getMethodSelect();
        if (methodSelect.getKind() != MEMBER_SELECT) {
          return null;
        }
        MemberSelectTree memberSelect = (MemberSelectTree) methodSelect;
  
        if (!invocation.getArguments().isEmpty()) {
          // TODO(cpovirk): Handle invocations with arguments.
          return null;
        }
        parts.addFirst(memberSelect.getIdentifier() + "()");
  
        ExpressionTree expression = memberSelect.getExpression();
        if (ACTUAL_METHOD.matches(expression, state)) {
          return '"' + Joiner.on('.').join(parts) + '"';
        }
        if (expression.getKind() != METHOD_INVOCATION) {
          return null;
        }
        invocation = (MethodInvocationTree) expression;
      }
    }