public void applyFunctionTagChanges(AddressSetView originAddressSet, int setting,
			Set<FunctionTag> discardTags, Set<FunctionTag> keepTags, TaskMonitor monitor)
			throws CancelledException {

		if ((setting != ProgramMergeFilter.REPLACE) && (setting != ProgramMergeFilter.MERGE)) {
			return;
		}

		monitor.setMessage("Applying function tags...");
		if (originAddressSet.isEmpty()) {
			return;
		}
		monitor.checkCancelled();

		AddressIterator addrIter = originAddressSet.getAddresses(true);
		for (long count = 0; addrIter.hasNext(); count++) {
			monitor.checkCancelled();
			Address originAddress = addrIter.next();

			if (count == PROGRESS_COUNTER_GRANULARITY) {
				monitor.setMessage(
					setting + " " + " function tags...   " + originAddress.toString(true));
				count = 0;
			}

			// This is the meat; either merge or replace depending on the user selection.
			if (setting == ProgramMergeFilter.MERGE) {
				mergeFunctionTags(originAddress, discardTags, keepTags);
			}
			else if (setting == ProgramMergeFilter.REPLACE) {
				replaceFunctionTags(originAddress);
			}
		}
	}
Merges/replaces tags of program2 into program1. When merging, tags that are in
conflict are replaced according to the user setting (ignore, replace, merge).

@param originAddressSet the addresses to be merged.
@param setting how to merge. IGNORE, REPLACE, MERGE
@param discardTags tags to keep out of the final result
@param keepTags tags to add to the final result
@param monitor the task monitor for notifying the user of this merge's progress.
@throws CancelledException if user cancels via the monitor.
Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMerge.java