[Refactor Xcode Objects] Enable navigator paths for file references.

Previously, the folder hierarchy of a file reference in project navigator was
forced to be the same as its physical folder hierarchy on disk.

This CL refactors xcode_object.h and xcode_object.cc to enable specifying a
navigator folder hierarchy when generating a file reference and it is allowed to
be completely different from the physical one.

This CL also corrects the mi-uses between "name" and "path" in PBXFileReference
and PBXGroup. Take "ios/tool.cc" as an example, name should be "tool.cc", while
path should be "ios/tool.cc", and they are different.

BUG=614818

Review-Url: https://codereview.chromium.org/2576773002
Cr-Original-Commit-Position: refs/heads/master@{#439429}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: d48f4812d85338487c72a7ab2b1c2db8d60dfdb0
diff --git a/tools/gn/xcode_object.cc b/tools/gn/xcode_object.cc
index dc5bfb8..039cb52 100644
--- a/tools/gn/xcode_object.cc
+++ b/tools/gn/xcode_object.cc
@@ -404,7 +404,7 @@
 }
 
 std::string PBXFileReference::Name() const {
-  return path_;
+  return name_;
 }
 
 void PBXFileReference::Print(std::ostream& out, unsigned indent) const {
@@ -417,16 +417,17 @@
     PrintProperty(out, rules, "explicitFileType", type_);
     PrintProperty(out, rules, "includeInIndex", 0u);
   } else {
-    base::StringPiece ext = FindExtension(&path_);
+    base::StringPiece ext = FindExtension(&name_);
     if (HasExplicitFileType(ext))
       PrintProperty(out, rules, "explicitFileType", GetSourceType(ext));
     else
       PrintProperty(out, rules, "lastKnownFileType", GetSourceType(ext));
   }
 
-  if (name_ != path_ && !name_.empty())
+  if (!name_.empty())
     PrintProperty(out, rules, "name", name_);
 
+  DCHECK(!path_.empty());
   PrintProperty(out, rules, "path", path_);
   PrintProperty(out, rules, "sourceTree",
                 type_.empty() ? "<group>" : "BUILT_PRODUCTS_DIR");
@@ -471,36 +472,39 @@
   return children_.back().get();
 }
 
-PBXFileReference* PBXGroup::AddSourceFile(const std::string& source_path) {
+PBXFileReference* PBXGroup::AddSourceFile(const std::string& navigator_path,
+                                          const std::string& source_path) {
+  DCHECK(!navigator_path.empty());
   DCHECK(!source_path.empty());
-  std::string::size_type sep = source_path.find("/");
+  std::string::size_type sep = navigator_path.find("/");
   if (sep == std::string::npos) {
     children_.push_back(base::MakeUnique<PBXFileReference>(
-        std::string(), source_path, std::string()));
+        navigator_path, source_path, std::string()));
     return static_cast<PBXFileReference*>(children_.back().get());
   }
 
   PBXGroup* group = nullptr;
-  base::StringPiece component(source_path.data(), sep);
+  base::StringPiece component(navigator_path.data(), sep);
   for (const auto& child : children_) {
     if (child->Class() != PBXGroupClass)
       continue;
 
     PBXGroup* child_as_group = static_cast<PBXGroup*>(child.get());
-    if (child_as_group->path_ == component) {
+    if (child_as_group->name_ == component) {
       group = child_as_group;
       break;
     }
   }
 
   if (!group) {
-    children_.push_back(base::WrapUnique(new PBXGroup(component.as_string())));
+    children_.push_back(base::WrapUnique(
+        new PBXGroup(component.as_string(), component.as_string())));
     group = static_cast<PBXGroup*>(children_.back().get());
   }
 
   DCHECK(group);
-  DCHECK(group->path_ == component);
-  return group->AddSourceFile(source_path.substr(sep + 1));
+  DCHECK(group->name_ == component);
+  return group->AddSourceFile(navigator_path.substr(sep + 1), source_path);
 }
 
 PBXObjectClass PBXGroup::Class() const {
@@ -530,7 +534,7 @@
   PrintProperty(out, rules, "children", children_);
   if (!name_.empty())
     PrintProperty(out, rules, "name", name_);
-  if (!path_.empty())
+  if (is_source_ && !path_.empty())
     PrintProperty(out, rules, "path", path_);
   PrintProperty(out, rules, "sourceTree", "<group>");
   out << indent_str << "};\n";
@@ -598,6 +602,7 @@
   main_group_.reset(new PBXGroup);
   sources_ = static_cast<PBXGroup*>(
       main_group_->AddChild(base::MakeUnique<PBXGroup>(source_path, "Source")));
+  sources_->set_is_source(true);
   products_ = static_cast<PBXGroup*>(main_group_->AddChild(
       base::MakeUnique<PBXGroup>(std::string(), "Product")));
   main_group_->AddChild(base::MakeUnique<PBXGroup>(std::string(), "Build"));
@@ -607,8 +612,10 @@
 
 PBXProject::~PBXProject() {}
 
-void PBXProject::AddSourceFile(const std::string& source_path) {
-  PBXFileReference* file_reference = sources_->AddSourceFile(source_path);
+void PBXProject::AddSourceFile(const std::string& navigator_path,
+                               const std::string& source_path) {
+  PBXFileReference* file_reference =
+      sources_->AddSourceFile(navigator_path, source_path);
   base::StringPiece ext = FindExtension(&source_path);
   if (!IsSourceFileForIndexing(ext))
     return;
diff --git a/tools/gn/xcode_object.h b/tools/gn/xcode_object.h
index 2ad43cc..83a776a 100644
--- a/tools/gn/xcode_object.h
+++ b/tools/gn/xcode_object.h
@@ -218,7 +218,10 @@
   const std::string& path() const { return path_; }
 
   PBXObject* AddChild(std::unique_ptr<PBXObject> child);
-  PBXFileReference* AddSourceFile(const std::string& source_path);
+  PBXFileReference* AddSourceFile(const std::string& navigator_path,
+                                  const std::string& source_path);
+  bool is_source() { return is_source_; }
+  void set_is_source(const bool is_source) { is_source_ = is_source; }
 
   // PBXObject implementation.
   PBXObjectClass Class() const override;
@@ -230,6 +233,7 @@
   std::vector<std::unique_ptr<PBXObject>> children_;
   std::string name_;
   std::string path_;
+  bool is_source_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(PBXGroup);
 };
@@ -271,7 +275,8 @@
              const PBXAttributes& attributes);
   ~PBXProject() override;
 
-  void AddSourceFile(const std::string& source_path);
+  void AddSourceFile(const std::string& navigator_path,
+                     const std::string& source_path);
   void AddAggregateTarget(const std::string& name,
                           const std::string& shell_script);
   void AddNativeTarget(const std::string& name,
diff --git a/tools/gn/xcode_writer.cc b/tools/gn/xcode_writer.cc
index 633a1c8..07b50e4 100644
--- a/tools/gn/xcode_writer.cc
+++ b/tools/gn/xcode_writer.cc
@@ -353,7 +353,7 @@
   for (const SourceFile& source : sources) {
     std::string source_file =
         RebasePath(source.value(), source_dir, absolute_source_path);
-    sources_for_indexing->AddSourceFile(source_file);
+    sources_for_indexing->AddSourceFile(source_file, source_file);
   }
 
   projects_.push_back(std::move(sources_for_indexing));