[iOS] Refactoring XcodeWriter::CreateProductsProject.

|XcodeWriter::CreateProductsProject| in xcode_writer.cc has evolved
into a giant function, so this CL makes it smaller by refactoring the
logics that add XCTest files for indexing and target dependencies into
two separate functions.

Bug: 709289
Change-Id: Icd2fd1cc5f925b680e25f488a42cbea3d2b53e9a
Reviewed-on: https://chromium-review.googlesource.com/568253
Commit-Queue: Yuke Liao <liaoyuke@chromium.org>
Reviewed-by: Sylvain Defresne <sdefresne@chromium.org>
Reviewed-by: Dirk Pranke <dpranke@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#486593}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: a88945a80077787acdf9b2a30b10febab058f1f4
diff --git a/tools/gn/xcode_writer.cc b/tools/gn/xcode_writer.cc
index fbcc069..a4c97ad 100644
--- a/tools/gn/xcode_writer.cc
+++ b/tools/gn/xcode_writer.cc
@@ -13,6 +13,7 @@
 
 #include "base/environment.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -168,6 +169,46 @@
     xctest_module_to_application_target->insert(std::make_pair(
         xctest_module_target, xctest_application_targets->back()));
   }
+
+  DCHECK_EQ(xctest_module_targets.size(), xctest_application_targets->size());
+  DCHECK_EQ(xctest_module_targets.size(),
+            xctest_module_to_application_target->size());
+}
+
+// Adds |base_pbxtarget| as a dependency of |dependent_pbxtarget| in the
+// generated Xcode project.
+void AddPBXTargetDependency(const PBXTarget* base_pbxtarget,
+                            PBXTarget* dependent_pbxtarget,
+                            const PBXProject* project) {
+  auto container_item_proxy =
+      base::MakeUnique<PBXContainerItemProxy>(project, base_pbxtarget);
+  auto dependency = base::MakeUnique<PBXTargetDependency>(
+      base_pbxtarget, std::move(container_item_proxy));
+
+  dependent_pbxtarget->AddDependency(std::move(dependency));
+}
+
+// Adds the corresponding test rig application target as dependency of xctest
+// module target in the generated Xcode project.
+void AddDependencyTargetForXCModuleTargets(
+    const std::vector<const Target*>& targets,
+    const TargetToPBXTarget& bundle_target_to_pbxtarget,
+    const PBXProject* project) {
+  for (const Target* target : targets) {
+    if (!IsXCTestModuleTarget(target))
+      continue;
+
+    const Target* test_application_target =
+        FindXCTestApplicationTarget(target, targets);
+    const PBXTarget* test_application_pbxtarget =
+        bundle_target_to_pbxtarget.at(test_application_target);
+    PBXTarget* module_pbxtarget = bundle_target_to_pbxtarget.at(target);
+    DCHECK(test_application_pbxtarget);
+    DCHECK(module_pbxtarget);
+
+    AddPBXTargetDependency(test_application_pbxtarget, module_pbxtarget,
+                           project);
+  }
 }
 
 // Searches the list of xctest files recursively under |target|.
@@ -221,6 +262,8 @@
     xctest_files_per_application_target->insert(
         std::make_pair(target, xctest_files_per_target[target]));
   }
+  DCHECK_EQ(application_targets.size(),
+            xctest_files_per_application_target->size());
 }
 
 // Add all source files for indexing, both private and public.
@@ -263,6 +306,27 @@
   }
 }
 
+// Add xctest files to the "Compiler Sources" of corresponding xctest native
+// targets.
+void AddXCTestFilesToXCTestModuleTarget(
+    const Target::FileList& xctest_file_list,
+    PBXNativeTarget* native_target,
+    PBXProject* project,
+    SourceDir source_dir,
+    const BuildSettings* build_settings) {
+  for (const SourceFile& source : xctest_file_list) {
+    std::string source_path = RebasePath(source.value(), source_dir,
+                                         build_settings->root_path_utf8());
+
+    // Test files need to be known to Xcode for proper indexing and for
+    // discovery of tests function for XCTest, but the compilation is done
+    // via ninja and thus must prevent Xcode from compiling the files by
+    // adding '-help' as per file compiler flag.
+    project->AddSourceFile(source_path, source_path, CompilerFlags::HELP,
+                           native_target);
+  }
+}
+
 class CollectPBXObjectsPerClassHelper : public PBXObjectVisitor {
  public:
   CollectPBXObjectsPerClassHelper() {}
@@ -464,12 +528,7 @@
   std::unique_ptr<PBXProject> main_project(
       new PBXProject("products", config_name, source_path, attributes));
 
-  SourceDir source_dir("//");
-  AddSourceFilesToProjectForIndexing(all_targets, main_project.get(),
-                                     source_dir, build_settings);
-
-  // Filter xctest module and application targets and find list of xctest files
-  // recursively under them.
+  // Filter xctest module and application targets.
   std::vector<const Target*> xctest_module_targets;
   FilterXCTestModuleTargets(targets, &xctest_module_targets);
 
@@ -480,21 +539,21 @@
   FindXCTestApplicationTargets(xctest_module_targets, targets,
                                &xctest_application_targets,
                                &xctest_module_to_application_target);
-  DCHECK_EQ(xctest_module_targets.size(), xctest_application_targets.size());
-  DCHECK_EQ(xctest_module_targets.size(),
-            xctest_module_to_application_target.size());
 
+  // Find list of xctest files recursively under them, and the files will be
+  // used for proper indexing and for discovery of tests function for XCTest.
   TargetToFileList xctest_files_per_application_target;
   FindXCTestFilesForApplicationTargets(xctest_application_targets,
                                        &xctest_files_per_application_target);
-  DCHECK_EQ(xctest_application_targets.size(),
-            xctest_files_per_application_target.size());
 
+  std::vector<const Target*> bundle_targets;
   TargetToPBXTarget bundle_target_to_pbxtarget;
 
   std::string build_path;
   std::unique_ptr<base::Environment> env(base::Environment::Create());
-
+  SourceDir source_dir("//");
+  AddSourceFilesToProjectForIndexing(all_targets, main_project.get(),
+                                     source_dir, build_settings);
   main_project->AddAggregateTarget(
       "All", GetBuildScript(root_target, ninja_extra_args, env.get()));
 
@@ -544,15 +603,18 @@
           xcode_extra_attributes["DEBUG_INFORMATION_FORMAT"] = "dwarf";
         }
 
-        PBXNativeTarget* native_target = main_project->AddNativeTarget(
-            pbxtarget_name, std::string(),
+        const std::string& target_output_name =
             RebasePath(target->bundle_data()
                            .GetBundleRootDirOutput(target->settings())
                            .value(),
-                       build_settings->build_dir()),
+                       build_settings->build_dir());
+        PBXNativeTarget* native_target = main_project->AddNativeTarget(
+            pbxtarget_name, std::string(), target_output_name,
             target->bundle_data().product_type(),
             GetBuildScript(pbxtarget_name, ninja_extra_args, env.get()),
             xcode_extra_attributes);
+
+        bundle_targets.push_back(target);
         bundle_target_to_pbxtarget.insert(
             std::make_pair(target, native_target));
 
@@ -560,23 +622,14 @@
           continue;
 
         // Add xctest files to the "Compiler Sources" of corresponding xctest
-        // native targets.
+        // native targets for proper indexing and for discovery of tests
+        // function for XCTest.
         const Target::FileList& xctest_file_list =
             xctest_files_per_application_target
                 [xctest_module_to_application_target[target]];
-
-        for (const SourceFile& source : xctest_file_list) {
-          std::string source_path = RebasePath(
-              source.value(), source_dir, build_settings->root_path_utf8());
-
-          // Test files need to be known to Xcode for proper indexing and for
-          // discovery of tests function for XCTest, but the compilation is done
-          // via ninja and thus must prevent Xcode from compiling the files by
-          // adding '-help' as per file compiler flag.
-          main_project->AddSourceFile(source_path, source_path,
-                                      CompilerFlags::HELP, native_target);
-        }
-
+        AddXCTestFilesToXCTestModuleTarget(xctest_file_list, native_target,
+                                           main_project.get(), source_dir,
+                                           build_settings);
         break;
       }
 
@@ -585,30 +638,12 @@
     }
   }
 
-  // Add corresponding application target as dependency of xctest module target
-  // so that application target is re-compiled when compiling xctest module
-  // target.
-  for (const Target* target : targets) {
-    if (target->output_type() != Target::CREATE_BUNDLE)
-      continue;
-    if (!IsXCTestModuleTarget(target))
-      continue;
-
-    const Target* application_target =
-        FindXCTestApplicationTarget(target, targets);
-    PBXTarget* application_pbxtarget =
-        bundle_target_to_pbxtarget[application_target];
-    DCHECK(application_pbxtarget);
-    PBXTarget* xctest_module_pbxtarget = bundle_target_to_pbxtarget[target];
-    DCHECK(xctest_module_pbxtarget);
-
-    std::unique_ptr<PBXContainerItemProxy> container_item_proxy(
-        new PBXContainerItemProxy(main_project.get(), application_pbxtarget));
-    std::unique_ptr<PBXTargetDependency> dependency(new PBXTargetDependency(
-        application_pbxtarget, std::move(container_item_proxy)));
-
-    xctest_module_pbxtarget->AddDependency(std::move(dependency));
-  }
+  // For XCTest, tests are compiled into the application bundle, thus adding
+  // the corresponding test rig application target as a dependency of xctest
+  // module target in the generated Xcode project so that the application target
+  // is re-compiled when compiling the xctest module target.
+  AddDependencyTargetForXCModuleTargets(
+      bundle_targets, bundle_target_to_pbxtarget, main_project.get());
 
   projects_.push_back(std::move(main_project));
 }