////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        protected ITaskItem [] GetOutOfDateSourcesFromCmdLineChanges(string expectedCommandLine, ITaskItem [] uncheckedSources)
        {
            //
            // Evaluate which (if any) of the `uncheckedSources` are already present in the command TLog.
            // If cached entries are found, identify whether this source should be considered "out of date".
            //

            if (TLogCommandFiles?.Length == 0)
            {
                return(Array.Empty <ITaskItem>());
            }

            Dictionary <string, ITaskItem> uncheckedSourcesRooted = new Dictionary <string, ITaskItem>();

            foreach (var uncheckedSource in uncheckedSources)
            {
                uncheckedSourcesRooted.Add(TrackedFileManager.ConvertToTrackerFormat(uncheckedSource), uncheckedSource);
            }

            var outOfDateSources = new HashSet <ITaskItem>();

            using StreamReader reader = File.OpenText(TLogCommandFiles[0].ItemSpec);

            for (string line = reader.ReadLine(); !string.IsNullOrEmpty(line); line = reader.ReadLine())
            {
                if (line.StartsWith("^"))
                {
                    var trackedFiles = line.Substring(1).Split('|');

                    string trackedCommandLine = reader.ReadLine();

                    foreach (string trackedFile in trackedFiles)
                    {
                        if (uncheckedSourcesRooted.TryGetValue(trackedFile, out ITaskItem match) && !string.Equals(trackedCommandLine, expectedCommandLine))
                        {
#if DEBUG
                            Log.LogMessageFromText($"[{GetType().Name}] Out of date source identified: {trackedFile}. Command lines differed.", MessageImportance.Low);

                            Log.LogMessageFromText($"[{GetType().Name}] Out of date source identified: {trackedFile}. Expected: {expectedCommandLine} ", MessageImportance.Low);

                            Log.LogMessageFromText($"[{GetType().Name}] Out of date source identified: {trackedFile}. Cached: {trackedCommandLine} ", MessageImportance.Low);
#endif

                            outOfDateSources.Add(match);
                        }
                    }
                }
            }

            return(outOfDateSources.ToArray());
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#if false
        protected override void OutputCommandTLog(ITaskItem commandFile, string responseFileCommands, string commandLineCommands)
        {
            //
            // Output a tracking file for each of the commands used in the previous build, and target sources to which they relate.
            //
            // *Keeps existing entries in the command log. Updates entries for sources which have been compiled/modified.*
            //

            if (TLogCommandFiles?.Length == 0)
            {
                throw new InvalidOperationException("TLogCommandFile is invalid");
            }

            //
            // Merge existing and new dictionaries. This is quite expensive, but means we can utilise a more simple base export implementation.
            //

            Dictionary <string, List <ITaskItem> > cachedCommandLogDictionary = GenerateCommandLinesFromTlogs(TLogCommandFiles);

            Dictionary <string, List <ITaskItem> > mergedCommandLogDictionary = new Dictionary <string, List <ITaskItem> > ();

            //
            // Add recently changed sources first, ensuring these take precedence.
            //

            foreach (KeyValuePair <string, List <ITaskItem> > entry in commandDictionary)
            {
                HashSet <string> mergedLogDictionaryListAsFullPaths = new HashSet <string> ();

                if (mergedCommandLogDictionary.TryGetValue(entry.Key, out List <ITaskItem> mergedLogDictionaryList))
                {
                    foreach (ITaskItem source in mergedLogDictionaryList)
                    {
                        string trackerFormat = TrackedFileManager.ConvertToTrackerFormat(source.GetMetadata("FullPath"));

                        if (!mergedLogDictionaryListAsFullPaths.Contains(trackerFormat))
                        {
                            mergedLogDictionaryListAsFullPaths.Add(trackerFormat);
                        }
                    }
                }
                else
                {
                    mergedLogDictionaryList = new List <ITaskItem> ();
                }

                foreach (ITaskItem source in entry.Value)
                {
                    string trackerFormat = TrackedFileManager.ConvertToTrackerFormat(source.GetMetadata("FullPath"));

                    if (!mergedLogDictionaryListAsFullPaths.Contains(trackerFormat))
                    {
                        mergedLogDictionaryList.Add(source);

                        mergedLogDictionaryListAsFullPaths.Add(trackerFormat);
                    }
                }

                mergedCommandLogDictionary [entry.Key] = mergedLogDictionaryList;
            }

            //
            // Continue by adding the remaining cached source commands, if they won't overwrite any existing entries.
            //

            foreach (KeyValuePair <string, List <ITaskItem> > entry in cachedCommandLogDictionary)
            {
                HashSet <string> mergedLogDictionaryListAsFullPaths = new HashSet <string> ();

                if (mergedCommandLogDictionary.TryGetValue(entry.Key, out List <ITaskItem> mergedLogDictionaryList))
                {
                    foreach (ITaskItem source in mergedLogDictionaryList)
                    {
                        string trackerFormat = TrackedFileManager.ConvertToTrackerFormat(source.GetMetadata("FullPath"));

                        if (!mergedLogDictionaryListAsFullPaths.Contains(trackerFormat))
                        {
                            mergedLogDictionaryListAsFullPaths.Add(trackerFormat);
                        }
                    }
                }
                else
                {
                    mergedLogDictionaryList = new List <ITaskItem> ();
                }

                foreach (ITaskItem source in entry.Value)
                {
                    string trackerFormat = TrackedFileManager.ConvertToTrackerFormat(source.GetMetadata("FullPath"));

                    if (!mergedLogDictionaryListAsFullPaths.Contains(trackerFormat))
                    {
                        mergedLogDictionaryList.Add(source);

                        mergedLogDictionaryListAsFullPaths.Add(trackerFormat);
                    }
                }

                mergedCommandLogDictionary [entry.Key] = mergedLogDictionaryList;
            }

            base.OutputCommandTLog(mergedCommandLogDictionary);
        }