@Nonnull
	public String apply() {
		String source = unit.getInputSource();

		// Get all named resolutions and replace them with their mapped alternatives in reverse order.
		List<NamedResolutions> pairs = new ArrayList<>();
		unit.visit(model -> {
			if (!model.getRange().isUnknown() && model instanceof NamedModel named) {
				Resolution resolution = model.resolve(resolver);
				if (!resolution.isUnknown() && !(resolution instanceof PrimitiveResolution))
					pairs.add(new NamedResolutions(named, resolution));
			}
			return true;
		});
		for (int i = pairs.size() - 1; i >= 0; i--) {
			NamedResolutions pair = pairs.get(i);
			NamedModel named = pair.named();
			Resolution resolution = pair.resolution();
			if (resolution instanceof ClassResolution classResolution) {
				source = replacePatternIn(named, source, getSimpleName(classResolution), getSimpleName(getMappedClass(classResolution)));
			} else if (resolution instanceof FieldResolution fieldResolution) {
				source = replacePatternIn(named, source, fieldResolution.getFieldEntry().getName(), getSimpleName(getMappedField(fieldResolution)));
			} else if (resolution instanceof MethodResolution methodResolution) {
				if (methodResolution.getMethodEntry().getName().equals("<init>")) {
					// Constructors get replaced as the owner name
					ClassResolution ownerResolution = methodResolution.getOwnerResolution();
					source = replacePatternIn(named, source, getSimpleName(ownerResolution), getSimpleName(getMappedClass(ownerResolution)));
				} else {
					source = replacePatternIn(named, source, methodResolution.getMethodEntry().getName(), getSimpleName(getMappedMethod(methodResolution)));
				}
			}
		}

		// Replace imports of mapped classes & members.
		IntermediateMappings intermediateMappings = mappings.exportIntermediate();
		for (int i = unit.getImports().size() - 1; i >= 0; i--) {
			ImportModel importModel = unit.getImports().get(i);
			Resolution resolution = importModel.resolve(resolver);
			if (resolution instanceof ClassResolution classResolution) {
				// Single class to map.
				String mappedName = getMappedClass(classResolution);
				if (mappedName != null) {
					String baseName = classResolution.getClassEntry().getName().replace('/', '.');
					source = replacePatternIn(importModel, source, baseName, mappedName.replace('/', '.'));
				}
			} else if (resolution instanceof MultiClassResolution multiClassResolution) {
				// Multiple classes to consider with a 'package.*' import.
				List<String> classesInPackage = multiClassResolution.getClassEntries().stream()
						.map(ClassEntry::getName)
						.toList();
				Set<String> unmappedClasses = new HashSet<>();
				Map<String, String> mappedClasses = new HashMap<>();
				for (String className : classesInPackage) {
					String mappedClassName = mappings.getMappedClassName(className);
					if (mappedClassName != null)
						mappedClasses.put(className, mappedClassName);
					else
						unmappedClasses.add(className);
				}

				// No classes were mapped, so we're good to go
				if (mappedClasses.isEmpty())
					continue;

				// Determine what new package names we need to import.
				int begin = importModel.getRange().begin();
				boolean removeExistingPackageImport = unmappedClasses.isEmpty();
				if (removeExistingPackageImport)
					source = source.replace(importModel.getSource(unit), "");
				for (String mappedClass : mappedClasses.values()) {
					if (mappedClass.indexOf('$') < 0) // Skip inner classes
						source = StringUtil.insert(source, begin, "import " + mappedClass.replace('/', '.') + ";\n");
				}
			} else if (resolution instanceof MultiMemberResolution multiMemberResolution) {
				ClassEntry ownerEntry = multiMemberResolution.getMemberEntries().getFirst().ownerEntry();

				// Rename the imported field/method names if they were mapped.
				if (importModel.getName().indexOf('*') < 0) {
					for (ClassMemberPair pair : multiMemberResolution.getMemberEntries()) {
						MemberEntry memberEntry = pair.memberEntry();
						String mappedMemberName;
						if (memberEntry instanceof FieldEntry fieldEntry) {
							mappedMemberName = getMappedField(ownerEntry, fieldEntry);
						} else if (memberEntry instanceof MethodEntry methodEntry) {
							mappedMemberName = getMappedMethod(ownerEntry, methodEntry);
						} else {
							mappedMemberName = null;
						}
						if (mappedMemberName != null) {
							source = replacePatternIn(importModel, source, "." + memberEntry.getName() + ";", "." + mappedMemberName + ";");
							break;
						}
					}
				}

				// If the owning class was renamed, then rename that.
				String mappedClass = getMappedClass(ownerEntry);
				if (mappedClass != null) {
					source = replacePatternIn(importModel, source,
							ownerEntry.getName().replace('/', '.'),
							mappedClass.replace('/', '.'));
				}
			}
		}

		// Replace package if the class got moved to a different package.
		if (unit.getDeclaredClasses().getFirst().resolve(resolver) instanceof ClassResolution resolution) {
			String mappedClass = getMappedClass(resolution);
			if (mappedClass != null) {
				int slashIndex = mappedClass.lastIndexOf('/');
				if (slashIndex > 0) {
					String mappedPackageName = mappedClass.substring(0, slashIndex);
					String packageName = unit.getPackage().getName().replace('.', '/');
					if (!packageName.equals(mappedPackageName)) {
						source = source.replace("package " + unit.getPackage().getName() + ";",
								"package " + mappedPackageName.replace('/', '.') + ";");
					}
				}
			}
		}

		return source;
	}
@return Modified source code based on the provided mappings.
recaf-core/src/main/java/software/coley/recaf/services/source/AstMapper.java