@Nullable
  Expectation findNotStrictExpectation(
      @Nullable Object mock,
      @Nonnull String mockClassDesc,
      @Nonnull String mockNameAndDesc,
      @Nonnull Object[] args) {
    boolean constructorInvocation = mockNameAndDesc.charAt(0) == '<';
    Expectation replayExpectationFound = null;

    // Note: new expectations might get added to the list, so a regular loop would cause a CME:
    for (int i = 0, n = notStrictExpectations.size(); i < n; i++) {
      Expectation expectation = notStrictExpectations.get(i);

      if (replayExpectationFound != null && expectation.recordPhase == null) {
        continue;
      }

      if (isMatchingInvocation(
              mock, mockClassDesc, mockNameAndDesc, constructorInvocation, expectation)
          && expectation.invocation.arguments.isMatch(args, instanceMap)) {
        if (expectation.recordPhase == null) {
          replayExpectationFound = expectation;
          continue;
        }

        if (constructorInvocation) {
          registerReplacementInstanceIfApplicable(mock, expectation.invocation);
        }

        return expectation;
      }
    }

    return replayExpectationFound;
  }
  @Nullable
  private Expectation findPreviousNotStrictExpectation(@Nonnull ExpectedInvocation newInvocation) {
    int n = notStrictExpectations.size();

    if (n == 0) {
      return null;
    }

    Object mock = newInvocation.instance;
    String mockClassDesc = newInvocation.getClassDesc();
    String mockNameAndDesc = newInvocation.getMethodNameAndDescription();
    boolean constructorInvocation = newInvocation.isConstructor();

    for (int i = 0; i < n; i++) {
      Expectation previousExpectation = notStrictExpectations.get(i);

      if (isMatchingInvocation(
              mock, mockClassDesc, mockNameAndDesc, constructorInvocation, previousExpectation)
          && isWithMatchingArguments(newInvocation, previousExpectation.invocation)) {
        return previousExpectation;
      }
    }

    return null;
  }