// VisibleForTesting
    protected boolean runGenerator(RuleGenerateWith generatorRule, Set<String> reboundTypeNames)
        throws UnableToCompleteException {
      boolean fixedPoint = true;
      StandardGeneratorContext generatorContext = getGeneratorContext();
      removePreviouslyReboundCombinations(generatorRule.getName(), reboundTypeNames);
      reboundTypeNames.removeAll(previouslyReboundTypeNames);

      for (String reboundTypeName : reboundTypeNames) {
        if (badRebindCombinations.contains(generatorRule.getName() + "-" + reboundTypeName)) {
          continue;
        }
        generatorNamesByPreviouslyReboundTypeName.put(reboundTypeName, generatorRule.getName());
        reboundTypeName = reboundTypeName.replace("$", ".");
        generatorRule.generate(logger, module.getProperties(), generatorContext, reboundTypeName);

        if (generatorContext.isDirty()) {
          fixedPoint = false;
          previouslyReboundTypeNames.add(reboundTypeName);
          // Ensure that cascading generations rerun properly.
          for (String generatedTypeName : generatorContext.getGeneratedUnitMap().keySet()) {
            generatorNamesByPreviouslyReboundTypeName.removeAll(generatedTypeName);
          }
          generatorContext.finish(logger);
        } else {
          badRebindCombinations.add(generatorRule.getName() + "-" + reboundTypeName);
        }
      }

      return fixedPoint;
    }
  public JExpression doRebind(String clsName, ReflectionGeneratorContext params)
      throws UnableToCompleteException {
    // generate
    params.getLogger().log(Type.INFO, "Binding magic class for " + clsName);
    // JType type = params.getClazz().getRefType();
    JDeclaredType type =
        params.getAst().searchForTypeBySource(params.getClazz().getRefType().getName());

    StandardGeneratorContext ctx = params.getGeneratorContext();
    Class<? extends Generator> generator = MagicClassGenerator.class;

    String result =
        ctx.runGenerator(params.getLogger(), generator, SourceUtil.toSourceName(type.getName()));
    ctx.finish(params.getLogger());

    params.getLogger().log(Type.INFO, "Generated Class Enhancer: " + result);
    JDeclaredType success = params.getAst().searchForTypeBySource(result);

    // Okay, we've generated the correct magic class subtype;
    // Now pull off its static accessor method to grab our generated class.

    for (JMethod method : success.getMethods()) {
      if (method.isStatic() && method.getName().equals("enhanceClass")) {
        JMethodCall call = new JMethodCall(method.getSourceInfo(), null, method);
        call.addArg(params.getClazz().makeStatement().getExpr());
        return call;
      }
    }
    params.getLogger().log(Type.ERROR, "Unable to load " + result + ".enhanceClass()");
    throw new UnableToCompleteException();
  }
 // VisibleForTesting
 void buildRuntimeRebindRegistrator(Set<String> allRootTypes) throws UnableToCompleteException {
   RuntimeRebindRegistratorGenerator runtimeRebindRegistratorGenerator =
       new RuntimeRebindRegistratorGenerator();
   StandardGeneratorContext generatorContext = getGeneratorContext();
   String runtimeRebindRegistratorTypeName =
       runtimeRebindRegistratorGenerator.generate(logger, generatorContext, module.getName());
   // Ensures that unification traverses and keeps the class.
   allRootTypes.add(runtimeRebindRegistratorTypeName);
   // Ensures that JProgram knows to index this class's methods so that later bootstrap
   // construction code is able to locate the FooRuntimeRebindRegistrator.register() function.
   jprogram.addIndexedTypeName(runtimeRebindRegistratorTypeName);
   jprogram.setRuntimeRebindRegistratorTypeName(runtimeRebindRegistratorTypeName);
   generatorContext.finish(logger);
 }
 // VisibleForTesting
 void buildPropertyProviderRegistrator(
     Set<String> allRootTypes,
     SortedSet<BindingProperty> bindingProperties,
     SortedSet<ConfigurationProperty> configurationProperties)
     throws UnableToCompleteException {
   PropertyProviderRegistratorGenerator propertyProviderRegistratorGenerator =
       new PropertyProviderRegistratorGenerator(bindingProperties, configurationProperties);
   StandardGeneratorContext generatorContext = getGeneratorContext();
   String propertyProviderRegistratorTypeName =
       propertyProviderRegistratorGenerator.generate(logger, generatorContext, module.getName());
   // Ensures that unification traverses and keeps the class.
   allRootTypes.add(propertyProviderRegistratorTypeName);
   // Ensures that JProgram knows to index this class's methods so that later bootstrap
   // construction code is able to locate the FooPropertyProviderRegistrator.register() function.
   jprogram.addIndexedTypeName(propertyProviderRegistratorTypeName);
   jprogram.setPropertyProviderRegistratorTypeSourceName(propertyProviderRegistratorTypeName);
   generatorContext.finish(logger);
 }