docs: @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  		if (lombokDisabled) return false;
  		if (roundEnv.processingOver()) {
  			cleanup.run();
  			return false;
  		}
  		
  		// We have: A sorted set of all priority levels: 'priorityLevels'
  		
  		// Step 1: Take all CUs which aren't already in the map. Give them the first priority level.
  		
  		String randomModuleName = null;
  		
  		for (Element element : roundEnv.getRootElements()) {
  			if (randomModuleName == null) randomModuleName = getModuleNameFor(element);
  			JCCompilationUnit unit = toUnit(element);
  			if (unit == null) continue;
  			if (roots.containsKey(unit)) continue;
  			roots.put(unit, priorityLevels[0]);
  		}
  		
  		while (true) {
  			// Step 2: For all CUs (in the map, not the roundEnv!), run them across all handlers at their current prio level.
  			
  			for (long prio : priorityLevels) {
  				List<JCCompilationUnit> cusForThisRound = new ArrayList<JCCompilationUnit>();
  				for (Map.Entry<JCCompilationUnit, Long> entry : roots.entrySet()) {
  					Long prioOfCu = entry.getValue();
  					if (prioOfCu == null || prioOfCu != prio) continue;
  					cusForThisRound.add(entry.getKey());
  				}
  				transformer.transform(prio, javacProcessingEnv.getContext(), cusForThisRound, cleanup);
  			}
  			
  			// Step 3: Push up all CUs to the next level. Set level to null if there is no next level.
  			
  			Set<Long> newLevels = new HashSet<Long>();
  			for (int i = priorityLevels.length - 1; i >= 0; i--) {
  				Long curLevel = priorityLevels[i];
  				Long nextLevel = (i == priorityLevels.length - 1) ? null : priorityLevels[i + 1];
  				List<JCCompilationUnit> cusToAdvance = new ArrayList<JCCompilationUnit>();
  				for (Map.Entry<JCCompilationUnit, Long> entry : roots.entrySet()) {
  					if (curLevel.equals(entry.getValue())) {
  						cusToAdvance.add(entry.getKey());
  						newLevels.add(nextLevel);
  					}
  				}
  				for (JCCompilationUnit unit : cusToAdvance) {
  					roots.put(unit, nextLevel);
  				}
  			}
  			newLevels.remove(null);
  			
  			// Step 4: If ALL values are null, quit. Else, either do another loop right now or force a resolution reset by forcing a new round in the annotation processor.
  			
  			if (newLevels.isEmpty()) return false;
  			newLevels.retainAll(priorityLevelsRequiringResolutionReset);
  			if (!newLevels.isEmpty()) {
  				// Force a new round to reset resolution. The next round will cause this method (process) to be called again.
  				forceNewRound(randomModuleName, javacFiler);
  				return false;
  			}
  			// None of the new levels need resolution, so just keep going.
  		}
  	}