/// <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. } } } } }