private void doProcess(RoundEnvironment roundEnv) {
    for (Element element : roundEnv.getElementsAnnotatedWith(Provided.class)) {
      providedChecker.checkProvidedParameter(element);
    }

    for (Element element : roundEnv.getElementsAnnotatedWith(AnnotationsToApply.class)) {
      checkAnnotationsToApply(element);
    }

    ImmutableListMultimap.Builder<PackageAndClass, FactoryMethodDescriptor> indexedMethodsBuilder =
        ImmutableListMultimap.builder();
    ImmutableSetMultimap.Builder<PackageAndClass, ImplementationMethodDescriptor>
        implementationMethodDescriptorsBuilder = ImmutableSetMultimap.builder();
    // Iterate over the classes and constructors that are annotated with @AutoFactory.
    for (Element element : roundEnv.getElementsAnnotatedWith(AutoFactory.class)) {
      Optional<AutoFactoryDeclaration> declaration = declarationFactory.createIfValid(element);
      if (declaration.isPresent()) {
        PackageAndClass factoryName = declaration.get().getFactoryName();
        TypeElement extendingType = declaration.get().extendingType();
        implementationMethodDescriptorsBuilder.putAll(
            factoryName, implementationMethods(extendingType, element));
        for (TypeElement implementingType : declaration.get().implementingTypes()) {
          implementationMethodDescriptorsBuilder.putAll(
              factoryName, implementationMethods(implementingType, element));
        }
      }

      ImmutableSet<FactoryMethodDescriptor> descriptors =
          factoryDescriptorGenerator.generateDescriptor(element);
      for (FactoryMethodDescriptor descriptor : descriptors) {
        indexedMethodsBuilder.put(descriptor.factoryName(), descriptor);
      }
    }

    ImmutableSetMultimap<PackageAndClass, ImplementationMethodDescriptor>
        implementationMethodDescriptors = implementationMethodDescriptorsBuilder.build();
    ImmutableListMultimap<PackageAndClass, FactoryMethodDescriptor> indexedMethods =
        indexedMethodsBuilder.build();
    ImmutableSetMultimap<String, PackageAndClass> factoriesBeingCreated =
        simpleNamesToNames(indexedMethods.keySet());
    FactoryWriter factoryWriter =
        new FactoryWriter(processingEnv, injectApi, factoriesBeingCreated);

    indexedMethods
        .asMap()
        .forEach(
            (factoryName, methodDescriptors) -> {
              if (methodDescriptors.isEmpty()) {
                // This shouldn't happen, but check anyway to avoid an exception for
                // methodDescriptors.iterator().next() below.
                return;
              }
              // Sort to ensure output is deterministic.
              ImmutableSortedSet.Builder<AnnotationMirror> annotationsBuilder =
                  ImmutableSortedSet.orderedBy(ANNOTATION_COMPARATOR);
              // The sets of classes that are mentioned in the `extending` and `implementing`
              // elements, respectively, of the @AutoFactory annotations for this factory.
              ImmutableSet.Builder<TypeMirror> extending = newTypeSetBuilder();
              ImmutableSortedSet.Builder<TypeMirror> implementing = newTypeSetBuilder();
              boolean publicType = false;
              Set<Boolean> allowSubclassesSet = new HashSet<>();
              boolean skipCreation = false;
              for (FactoryMethodDescriptor methodDescriptor : methodDescriptors) {
                annotationsBuilder.addAll(methodDescriptor.declaration().annotations());
                extending.add(methodDescriptor.declaration().extendingType().asType());
                for (TypeElement implementingType :
                    methodDescriptor.declaration().implementingTypes()) {
                  implementing.add(implementingType.asType());
                }
                publicType |= methodDescriptor.publicMethod();
                allowSubclassesSet.add(methodDescriptor.declaration().allowSubclasses());
                if (allowSubclassesSet.size() > 1) {
                  skipCreation = true;
                  messager.printMessage(
                      Kind.ERROR,
                      "Cannot mix allowSubclasses=true and allowSubclasses=false in one factory.",
                      methodDescriptor.declaration().target(),
                      methodDescriptor.declaration().mirror(),
                      methodDescriptor.declaration().valuesMap().get("allowSubclasses"));
                }
              }
              // The set can't be empty because we eliminated methodDescriptors.isEmpty() above.
              boolean allowSubclasses = allowSubclassesSet.iterator().next();
              if (!skipCreation) {
                try {
                  factoryWriter.writeFactory(
                      FactoryDescriptor.create(
                          factoryName,
                          annotationsBuilder.build(),
                          Iterables.getOnlyElement(extending.build()),
                          implementing.build(),
                          publicType,
                          ImmutableSet.copyOf(methodDescriptors),
                          implementationMethodDescriptors.get(factoryName),
                          allowSubclasses));
                } catch (IOException e) {
                  messager.printMessage(Kind.ERROR, "failed: " + e);
                }
              }
            });
  }
If non-null, we will call this whenever the {@link #process} method is called, giving it one of
the {@code @AutoFactory} elements, and do nothing else.
factory/src/main/java/com/google/auto/factory/processor/AutoFactoryProcessor.java