private void updateTable() {
		ObservableList<VariableData> items = table.getItems();
		items.clear();

		// Collect all variable usage information from the AST.
		AstUsages emptyUsage = AstUsages.EMPTY_USAGE;
		Map<String, AstUsages> variableUsages = new HashMap<>();
		BiConsumer<String, ASTElement> readUpdater = (name, element) -> {
			AstUsages existing = variableUsages.getOrDefault(name, emptyUsage);
			variableUsages.put(name, existing.withNewRead(element));
		};
		BiConsumer<String, ASTElement> writeUpdater = (name, element) -> {
			AstUsages existing = variableUsages.getOrDefault(name, emptyUsage);
			variableUsages.put(name, existing.withNewWrite(element));
		};
		if (astElements != null) {
			Consumer<ASTMethod> methodConsumer = astMethod -> {
				if (currentMethod != null && !Objects.equals(currentMethod.getName(), astMethod.getName().literal()))
					return;
				for (ASTIdentifier parameter : astMethod.parameters()) {
					String literalName = parameter.literal();
					variableUsages.putIfAbsent(literalName, emptyUsage.asParameter());
				}
				ASTCode code = astMethod.code();
				if (code == null)
					return;
				for (ASTInstruction instruction : code.instructions()) {
					String insnName = instruction.identifier().content();
					if (insnName == null)
						continue;
					boolean isLoad = insnName.endsWith("load");
					boolean isStore = insnName.endsWith("store");
					if (((isLoad || isStore) && insnName.charAt(1) != 'a') || insnName.equals("iinc")) {
						List<ASTElement> arguments = instruction.arguments();
						if (!arguments.isEmpty()) {
							ASTElement arg = arguments.get(0);
							String varName = arg instanceof ASTIdentifier identifierArg ?
									identifierArg.literal() : arg.content();
							if (isLoad) {
								readUpdater.accept(varName, instruction);
							} else {
								writeUpdater.accept(varName, instruction);
							}
						}
					}
				}
			};
			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);
						}
					}
				}
			}
		}

		// Populate the variables map from the stack analysis results.
		AnalysisResults analysisResults = analysisLookup.results(currentMethod.getName(), currentMethod.getDescriptor());
		if (analysisResults != null && !analysisResults.frames().isEmpty()) {
			// Linked map for ordering
			Map<String, VariableData> variables = new LinkedHashMap<>();

			// In JASM variables are un-scoped, so the last frame should have all entries.
			analysisResults.frames().values().stream()
					.flatMap(Frame::locals)
					.distinct()
					.forEach(local -> {
						String localName = local.name();
						VariableData data = VariableData.adaptFrom(local, variableUsages.getOrDefault(localName, emptyUsage));
						variables.put(localName, data);
					});

			// In some cases, the last frame may not have some entries.
			// This generally means there is either a problem with the code or with JASM.
			// Either way, reporting them here with a bogus type is good for diagnosing the issue.
			variableUsages.forEach((name, usage) -> {
				if (!variables.containsKey(name))
					variables.put(name, new VariableData(name, INVALID_VAR_TYPE_MARKER, usage));
			});

			// Add all found items to the table.
			items.addAll(variables.values());
		}
	}
Handles updating the {@link VarHighlightLineFactory}.
<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/JvmVariablesPane.java