docs: Changes findChanges(InvocationInfo invocationInfo) {
      /* Methods with one or fewer parameters cannot possibly have a swap */
      if (invocationInfo.formalParameters().size() <= 1) {
        return Changes.empty();
      }
  
      /* Sometimes we don't have enough actual parameters. This seems to happen sometimes with calls
       * to super and javac finds two parameters arg0 and arg1 and no arguments */
      if (invocationInfo.actualParameters().size() < invocationInfo.formalParameters().size()) {
        return Changes.empty();
      }
  
      ImmutableList<Parameter> formals =
          Parameter.createListFromVarSymbols(invocationInfo.formalParameters());
      ImmutableList<Parameter> actuals =
          Parameter.createListFromExpressionTrees(
              invocationInfo.actualParameters().subList(0, invocationInfo.formalParameters().size()));
  
      Costs costs = new Costs(formals, actuals);
  
      /* Set the distance between a pair to Inf if not assignable */
      costs
          .viablePairs()
          .filter(ParameterPair::isAlternativePairing)
          .filter(p -> !p.actual().isAssignableTo(p.formal(), invocationInfo.state()))
          .forEach(p -> costs.invalidatePair(p));
  
      /* If there are no formal parameters which are assignable to any alternative actual parameters
      then we can stop without trying to look for permutations */
      if (costs.viablePairs().noneMatch(ParameterPair::isAlternativePairing)) {
        return Changes.empty();
      }
  
      /* Set the lexical distance between pairs */
      costs.viablePairs().forEach(p -> costs.updatePair(p, distanceFunction().apply(p)));
  
      Changes changes = costs.computeAssignments();
  
      if (changes.isEmpty()) {
        return changes;
      }
  
      /* Only keep this change if all of the heuristics match */
      for (Heuristic heuristic : heuristics()) {
        if (!heuristic.isAcceptableChange(
            changes, invocationInfo.tree(), invocationInfo.symbol(), invocationInfo.state())) {
          return Changes.empty();
        }
      }
      return changes;
    }