/// <summary>
        /// Parses the input and output files for copy tasks of given target.
        /// </summary>
        private static void ParseCopyTask(
            ProjectTargetInstance target,
            ProjectInstance projectInstance,
            ProjectPredictionReporter predictionReporter)
        {
            // Get all Copy tasks from targets.
            List <ProjectTaskInstance> tasks = target.Tasks
                                               .Where(task => string.Equals(task.Name, CopyTaskName, StringComparison.Ordinal))
                                               .ToList();

            if (tasks.Any() && projectInstance.EvaluateConditionCarefully(target.Condition))
            {
                foreach (ProjectTaskInstance task in tasks)
                {
                    if (projectInstance.EvaluateConditionCarefully(task.Condition))
                    {
                        var inputs = new FileExpressionList(
                            task.Parameters[CopyTaskSourceFiles],
                            projectInstance,
                            task);
                        if (inputs.NumExpressions == 0)
                        {
                            continue;
                        }

                        foreach (var file in inputs.DedupedFiles)
                        {
                            predictionReporter.ReportInputFile(file);
                        }

                        bool hasDestinationFolder = task.Parameters.TryGetValue(
                            CopyTaskDestinationFolder,
                            out string destinationFolder);
                        bool hasDestinationFiles = task.Parameters.TryGetValue(
                            CopyTaskDestinationFiles,
                            out string destinationFiles);

                        if (hasDestinationFiles || hasDestinationFolder)
                        {
                            // Having both is an MSBuild violation, which it will complain about.
                            if (hasDestinationFolder && hasDestinationFiles)
                            {
                                continue;
                            }

                            string destination = destinationFolder ?? destinationFiles;

                            var outputs = new FileExpressionList(destination, projectInstance, task);

                            // When using batch tokens, the user should specify exactly one total token, and it must appear in both the input and output.
                            // Doing otherwise should be a BuildCop error. If not using batch tokens, then any number of other tokens is fine.
                            if ((outputs.NumBatchExpressions == 1 && outputs.NumExpressions == 1 &&
                                 inputs.NumBatchExpressions == 1 && inputs.NumExpressions == 1) ||
                                (outputs.NumBatchExpressions == 0 && inputs.NumBatchExpressions == 0))
                            {
                                ProcessOutputs(inputs, outputs, hasDestinationFolder, predictionReporter);
                            }
                            else
                            {
                                // Ignore case we cannot handle.
                            }
                        }
                        else
                        {
                            // Ignore malformed case.
                        }
                    }
                }
            }
        }