private void updateModel() {
		// Skip if we've not selected a method
		if (currentMethod == null) {
			model = Collections.emptyList();
			return;
		}

		// Collect all label usage information from the AST.
		AstUsages emptyUsage = AstUsages.EMPTY_USAGE;
		Map<String, AstUsages> labelUsages = new HashMap<>();
		BiConsumer<String, ASTElement> readUpdater = (name, element) -> {
			AstUsages existing = labelUsages.getOrDefault(name, emptyUsage);
			labelUsages.put(name, existing.withNewRead(element));
		};
		BiConsumer<String, ASTElement> writeUpdater = (name, element) -> {
			AstUsages existing = labelUsages.getOrDefault(name, emptyUsage);
			labelUsages.put(name, existing.withNewWrite(element));
		};
		if (astElements != null) {
			Consumer<ASTMethod> methodConsumer = astMethod -> {
				if (currentMethod != null && !Objects.equals(currentMethod.getName(), astMethod.getName().literal()))
					return;
				ASTCode code = astMethod.code();
				if (code == null)
					return;
				for (ASTInstruction instruction : code.instructions()) {
					if (instruction instanceof ASTLabel label) {
						readUpdater.accept(label.identifier().content(), label);
					} else {
						String insnName = instruction.identifier().content();
						List<ASTElement> arguments = instruction.arguments();
						if (!arguments.isEmpty()) {
							if (INSN_SET.contains(insnName)) {
								writeUpdater.accept(arguments.getLast().content(), instruction);
							} else if ("tableswitch".equals(insnName)) {
								if (!instruction.arguments().isEmpty() && instruction.arguments().getFirst() instanceof ASTObject switchObj) {
									ASTArray cases = switchObj.value("cases");
									ASTElement defaultCase = switchObj.value("default");
									cases.values().forEach(caseAst -> writeUpdater.accept(caseAst.content(), caseAst));
									writeUpdater.accept(defaultCase.content(), defaultCase);
								}
							} else if ("lookupswitch".equals(insnName)) {
								if (!instruction.arguments().isEmpty() && instruction.arguments().getFirst() instanceof ASTObject switchObj) {
									ASTElement defaultCase = switchObj.value("default");
									writeUpdater.accept(defaultCase.content(), defaultCase);
									switchObj.values().pairs().forEach(pair -> {
										writeUpdater.accept(pair.second().content(), pair.first());
									});
								}
							}
						}
					}
				}
			};
			for (ASTElement astElement : astElements) {
				if (astElement instanceof ASTMethod astMethod) {
					methodConsumer.accept(astMethod);
				} else if (astElement instanceof ASTClass astClass) {
					for (ASTElement child : astClass.children()) {
						if (child instanceof ASTMethod astMethod) {
							methodConsumer.accept(astMethod);
						}
					}
				}
			}
		}
		model = labelUsages.entrySet().stream()
				.filter(e -> !e.getValue().readers().isEmpty()) // Must have a label declaration
				.map(e -> new LabelData(e.getKey(), e.getValue(), new IntBox(-1), new Box<>()))
				.sorted(Comparator.comparing(LabelData::name))
				.toList();
		model.forEach(data -> {
			List<LabelData> overlapping = data.computeOverlapping(model);
			IntBox slot = data.lineSlot();
			int slotIndex = 0;
			while (true) {
				incr:
				{
					for (LabelData d : overlapping) {
						if (slotIndex == d.lineSlot().get()) {
							slotIndex++;
							break incr;
						}
					}
					break;
				}
			}
			slot.set(slotIndex);
		});
	}
Handles updating the {@link ControlFlowLineFactory}.
<p/>
This logic is shoe-horned into here <i>(for now)</i> because
the variable tracking logic is internal to this class only.

@param caretChange
		Caret pos change.
recaf-ui/src/main/java/software/coley/recaf/ui/pane/editing/assembler/ControlFlowLines.java