/**
   * Chooses a name to use for renaming in each equivalence class and maps each type in that class
   * to it.
   */
  private Map<T, String> buildPropNames(UnionFind<T> types, String name) {
    Map<T, String> names = Maps.newHashMap();
    for (Set<T> set : types.allEquivalenceClasses()) {
      checkState(!set.isEmpty());

      String typeName = null;
      for (T type : set) {
        if (typeName == null || type.toString().compareTo(typeName) < 0) {
          typeName = type.toString();
        }
      }

      String newName;
      if ("{...}".equals(typeName)) {
        newName = name;
      } else {
        newName = typeName.replaceAll("[^\\w$]", "_") + "$" + name;
      }

      for (T type : set) {
        names.put(type, newName);
      }
    }
    return names;
  }
    /** Invalidates any types related to invalid types. */
    void expandTypesToSkip() {
      // If we are not going to rename any properties, then we do not need to
      // update the list of invalid types, as they are all invalid.
      if (shouldRename()) {
        int count = 0;
        while (true) {
          // It should usually only take one time through this do-while.
          checkState(++count < 10, "Stuck in loop expanding types to skip.");

          // Make sure that the representative type for each type to skip is
          // marked as being skipped.
          Set<T> rootTypesToSkip = Sets.newHashSet();
          for (T subType : typesToSkip) {
            rootTypesToSkip.add(types.find(subType));
          }
          typesToSkip.addAll(rootTypesToSkip);

          Set<T> newTypesToSkip = Sets.newHashSet();
          Set<T> allTypes = types.elements();
          int originalTypesSize = allTypes.size();
          for (T subType : allTypes) {
            if (!typesToSkip.contains(subType) && typesToSkip.contains(types.find(subType))) {
              newTypesToSkip.add(subType);
            }
          }

          for (T newType : newTypesToSkip) {
            addTypeToSkip(newType);
          }

          // If there were not any new types added, we are done here.
          if (types.elements().size() == originalTypesSize) {
            break;
          }
        }
      }
    }
 /** Returns true if any instance of this property should be renamed. */
 boolean shouldRename() {
   return !skipRenaming && types != null && types.allEquivalenceClasses().size() > 1;
 }