docs: private JavaFile generateModuleAdapter(TypeElement type,
        Map<String, Object> module, List<ExecutableElement> providerMethods) {
      Object[] staticInjections = (Object[]) module.get("staticInjections");
      Object[] injects = (Object[]) module.get("injects");
      Object[] includes = (Object[]) module.get("includes");
      boolean overrides = (Boolean) module.get("overrides");
      boolean complete = (Boolean) module.get("complete");
      boolean library = (Boolean) module.get("library");
  
      List<Object> duplicateInjects = extractDuplicates(injects);
      if (!duplicateInjects.isEmpty()) {
        error("'injects' list contains duplicate entries: " + duplicateInjects, type);
      }
      List<Object> duplicateIncludes = extractDuplicates(includes);
      if (!duplicateIncludes.isEmpty()) {
        error("'includes' list contains duplicate entries: " + duplicateIncludes, type);
      }
  
      ClassName moduleClassName = ClassName.get(type);
      ClassName adapterClassName = Util.adapterName(moduleClassName, MODULE_ADAPTER_SUFFIX);
  
      TypeSpec.Builder adapterBuilder = TypeSpec.classBuilder(adapterClassName.simpleName())
          .addOriginatingElement(type)
          .addJavadoc(AdapterJavadocs.MODULE_TYPE, Provides.class)
          .superclass(ParameterizedTypeName.get(ClassName.get(ModuleAdapter.class), moduleClassName))
          .addModifiers(PUBLIC, FINAL);
  
      adapterBuilder.addField(FieldSpec.builder(String[].class, "INJECTS")
          .addModifiers(PRIVATE, STATIC, FINAL)
          .initializer("$L", injectsInitializer(injects))
          .build());
      adapterBuilder.addField(FieldSpec.builder(ARRAY_OF_CLASS, "STATIC_INJECTIONS")
          .addModifiers(PRIVATE, STATIC, FINAL)
          .initializer("$L", staticInjectionsInitializer(staticInjections))
          .build());
      adapterBuilder.addField(FieldSpec.builder(ARRAY_OF_CLASS, "INCLUDES")
          .addModifiers(PRIVATE, STATIC, FINAL)
          .initializer("$L", includesInitializer(type, includes))
          .build());
      adapterBuilder.addMethod(MethodSpec.constructorBuilder()
          .addModifiers(PUBLIC)
          .addStatement("super($T.class, INJECTS, STATIC_INJECTIONS, $L /*overrides*/, "
                  + "INCLUDES, $L /*complete*/, $L /*library*/)",
              type.asType(), overrides, complete, library)
          .build());
  
      ExecutableElement noArgsConstructor = getNoArgsConstructor(type);
      if (noArgsConstructor != null && isCallableConstructor(noArgsConstructor)) {
        adapterBuilder.addMethod(MethodSpec.methodBuilder("newModule")
            .addAnnotation(Override.class)
            .addModifiers(PUBLIC)
            .returns(moduleClassName)
            .addStatement("return new $T()", type.asType())
            .build());
      }
  
      // Caches.
      Map<ExecutableElement, ClassName> methodToClassName
          = new LinkedHashMap<ExecutableElement, ClassName>();
      Map<String, AtomicInteger> methodNameToNextId = new LinkedHashMap<String, AtomicInteger>();
  
      if (!providerMethods.isEmpty()) {
        MethodSpec.Builder getBindings = MethodSpec.methodBuilder("getBindings")
            .addJavadoc(AdapterJavadocs.GET_DEPENDENCIES_METHOD)
            .addAnnotation(Override.class)
            .addModifiers(PUBLIC)
            .addParameter(BindingsGroup.class, "bindings")
            .addParameter(moduleClassName, "module");
  
        for (ExecutableElement providerMethod : providerMethods) {
          Provides provides = providerMethod.getAnnotation(Provides.class);
          switch (provides.type()) {
            case UNIQUE: {
              getBindings.addStatement("bindings.contributeProvidesBinding($S, new $T(module))",
                  GeneratorKeys.get(providerMethod),
                  bindingClassName(adapterClassName, providerMethod, methodToClassName,
                      methodNameToNextId));
              break;
            }
            case SET: {
              getBindings.addStatement("$T.add(bindings, $S, new $T(module))",
                  SetBinding.class,
                  GeneratorKeys.getSetKey(providerMethod),
                  bindingClassName(adapterClassName, providerMethod, methodToClassName,
                      methodNameToNextId));
              break;
            }
            case SET_VALUES: {
              getBindings.addStatement("$T.add(bindings, $S, new $T(module))",
                  SetBinding.class,
                  GeneratorKeys.get(providerMethod),
                  bindingClassName(adapterClassName, providerMethod, methodToClassName,
                      methodNameToNextId));
              break;
            }
            default:
              throw new AssertionError("Unknown @Provides type " + provides.type());
          }
        }
        adapterBuilder.addMethod(getBindings.build());
      }
  
      for (ExecutableElement providerMethod : providerMethods) {
        adapterBuilder.addType(generateProvidesAdapter(moduleClassName, adapterClassName,
            providerMethod, methodToClassName, methodNameToNextId, library));
      }
  
      return JavaFile.builder(adapterClassName.packageName(), adapterBuilder.build())
          .addFileComment(AdapterJavadocs.GENERATED_BY_DAGGER)
          .build();
    }