  private Map<String, Binding<?>> processCompleteModule(TypeElement rootModule) {
    Map<String, TypeElement> allModules = new LinkedHashMap<String, TypeElement>();
    collectIncludesRecursively(rootModule, allModules);
    Linker linker = new Linker(null, new CompileTimePlugin(processingEnv),
        new ReportingErrorHandler(processingEnv, rootModule.getQualifiedName().toString()));
    synchronized (linker) {
      Map<String, Binding<?>> baseBindings = new LinkedHashMap<String, Binding<?>>();
      Map<String, Binding<?>> overrideBindings = new LinkedHashMap<String, Binding<?>>();
      for (TypeElement module : allModules.values()) {
        Map<String, Object> annotation = CodeGen.getAnnotation(Module.class, module);
        boolean overrides = (Boolean) annotation.get("overrides");
        Map<String, Binding<?>> addTo = overrides ? overrideBindings : baseBindings;
        for (Object entryPoint : (Object[]) annotation.get("entryPoints")) {
          linker.requestBinding(GeneratorKeys.rawMembersKey((TypeMirror) entryPoint),
              module.getQualifiedName().toString(), false);
        }
        for (Element enclosed : module.getEnclosedElements()) {
          Provides provides = enclosed.getAnnotation(Provides.class);
          if (provides == null) {
            continue;
          }
          ExecutableElement providerMethod = (ExecutableElement) enclosed;
          String key = GeneratorKeys.get(providerMethod);
          ProviderMethodBinding binding = new ProviderMethodBinding(key, providerMethod);
          switch (provides.type()) {
            case UNIQUE:
              ProviderMethodBinding clobbered = (ProviderMethodBinding) addTo.put(key, binding);
              if (clobbered != null) {
                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
                    "Duplicate bindings for " + key
                        + ": " + shortMethodName(clobbered.method)
                        + ", " + shortMethodName(binding.method),
                    binding.method);
              }
              break;
            case SET:
              String elementKey = GeneratorKeys.getElementKey(providerMethod);
              SetBinding.add(addTo, elementKey, binding);
              break;
            default:
              throw new AssertionError("Unknown @Provides type " + provides.type());
          }
        }
      }
      linker.installBindings(baseBindings);
      linker.installBindings(overrideBindings);
      return linker.linkAll();
    }
  }

  private Map<String, Binding<?>> processCompleteModule(TypeElement rootModule) {
    Map<String, TypeElement> allModules = new LinkedHashMap<String, TypeElement>();
    collectIncludesRecursively(rootModule, allModules);
    Linker linker = new Linker(null, new CompileTimePlugin(processingEnv),
        new ReportingErrorHandler(processingEnv, rootModule.getQualifiedName().toString()));
    synchronized (linker) {
      Map<String, Binding<?>> baseBindings = new LinkedHashMap<String, Binding<?>>();
      Map<String, Binding<?>> overrideBindings = new LinkedHashMap<String, Binding<?>>();
      for (TypeElement module : allModules.values()) {
        Map<String, Object> annotation = CodeGen.getAnnotation(Module.class, module);
        boolean overrides = (Boolean) annotation.get("overrides");
        Map<String, Binding<?>> addTo = overrides ? overrideBindings : baseBindings;
        for (Object entryPoint : (Object[]) annotation.get("entryPoints")) {
          linker.requestBinding(GeneratorKeys.rawMembersKey((TypeMirror) entryPoint),
              module.getQualifiedName().toString(), false);
        }
        for (Element enclosed : module.getEnclosedElements()) {
          Provides provides = enclosed.getAnnotation(Provides.class);
          if (provides == null) {
            continue;
          }
          ExecutableElement providerMethod = (ExecutableElement) enclosed;
          String key = GeneratorKeys.get(providerMethod);
          ProviderMethodBinding binding = new ProviderMethodBinding(key, providerMethod);
          switch (provides.type()) {
            case UNIQUE:
              ProviderMethodBinding clobbered = (ProviderMethodBinding) addTo.put(key, binding);
              if (clobbered != null) {
                String msg = "Duplicate bindings for " + key;
                if (overrides) {
                  msg += " in override module(s) - cannot override an override";
                }
                msg += ": " + shortMethodName(clobbered.method)
                    + ", " + shortMethodName(binding.method);
                processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg,
                    binding.method);
              }
              break;
            case SET:
              String elementKey = GeneratorKeys.getElementKey(providerMethod);
              SetBinding.add(addTo, elementKey, binding);
              break;
            default:
              throw new AssertionError("Unknown @Provides type " + provides.type());
          }
        }
      }
      linker.installBindings(baseBindings);
      linker.installBindings(overrideBindings);
      return linker.linkAll();
    }
  }
