Use WithoutPathExpansion on DictionaryValue in GN.

The normal 'Set' methods on DictionaryValue scan for '.' in the path and
assume that the '.' indexes into an inner DictionaryValue. At no point
does gn appear to desire this behavior, so call the WithoutPathExpansion
variants instead.

This is mandatory when the path is user supplied, as it may have a '.'
This change was motivated by a target named like 'x.y' which caused

gn desc config //:x.y --format=json

to produce something like

"//:x": {
  "y": {
    "args": [ ... ]
    ...
  }
}

and similar issues when producing the project.json from the json ide
generator.

When the path is a constant which is known not to contain '.' there is
no behavioral change, but the extra work of scanning for the '.' is
avoided. In addition, if all uses are of the WithoutPathExpansion
variant then it becomes much less likely that similar errors will be
introduced in the future.

Review-Url: https://codereview.chromium.org/2363193002
Cr-Original-Commit-Position: refs/heads/master@{#421005}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: d51d3527da33b8f736dda1e99bcd9dc1586b366f
diff --git a/tools/gn/analyzer.cc b/tools/gn/analyzer.cc
index 011b77b..06f9336 100644
--- a/tools/gn/analyzer.cc
+++ b/tools/gn/analyzer.cc
@@ -102,7 +102,7 @@
 void WriteString(base::DictionaryValue& dict,
                  const std::string& key,
                  const std::string& value) {
-  dict.SetString(key, value);
+  dict.SetStringWithoutPathExpansion(key, value);
 };
 
 void WriteLabels(const Label& default_toolchain,
@@ -115,7 +115,7 @@
     strings.push_back(l.GetUserVisibleName(default_toolchain));
   std::sort(strings.begin(), strings.end());
   value->AppendStrings(strings);
-  dict.Set(key, std::move(value));
+  dict.SetWithoutPathExpansion(key, std::move(value));
 }
 
 Label AbsoluteOrSourceAbsoluteStringToLabel(const Label& default_toolchain,
@@ -207,7 +207,8 @@
     if (outputs.compile_includes_all) {
       auto compile_targets = base::WrapUnique(new base::ListValue());
       compile_targets->AppendString("all");
-      value->Set("compile_targets", std::move(compile_targets));
+      value->SetWithoutPathExpansion("compile_targets",
+                                     std::move(compile_targets));
     } else {
       WriteLabels(default_toolchain, *value, "compile_targets",
                   outputs.compile_labels);
diff --git a/tools/gn/command_desc.cc b/tools/gn/command_desc.cc
index acb8077..27117c5 100644
--- a/tools/gn/command_desc.cc
+++ b/tools/gn/command_desc.cc
@@ -462,16 +462,18 @@
     auto res = base::MakeUnique<base::DictionaryValue>();
     if (!target_matches.empty()) {
       for (const auto* target : target_matches) {
-        res->Set(target->label().GetUserVisibleName(
-                     target->settings()->default_toolchain_label()),
-                 DescBuilder::DescriptionForTarget(
-                     target, what_to_print, cmdline->HasSwitch(kAll),
-                     cmdline->HasSwitch(kTree), cmdline->HasSwitch(kBlame)));
+        res->SetWithoutPathExpansion(
+            target->label().GetUserVisibleName(
+                target->settings()->default_toolchain_label()),
+            DescBuilder::DescriptionForTarget(
+                target, what_to_print, cmdline->HasSwitch(kAll),
+                cmdline->HasSwitch(kTree), cmdline->HasSwitch(kBlame)));
       }
     } else if (!config_matches.empty()) {
       for (const auto* config : config_matches) {
-        res->Set(config->label().GetUserVisibleName(false),
-                 DescBuilder::DescriptionForConfig(config, what_to_print));
+        res->SetWithoutPathExpansion(
+            config->label().GetUserVisibleName(false),
+            DescBuilder::DescriptionForConfig(config, what_to_print));
       }
     }
     std::string s;
diff --git a/tools/gn/desc_builder.cc b/tools/gn/desc_builder.cc
index aca148c..3e2aaa0 100644
--- a/tools/gn/desc_builder.cc
+++ b/tools/gn/desc_builder.cc
@@ -159,13 +159,14 @@
                                const ConfigValues& values) {
     if (what(variables::kPrecompiledHeader) &&
         !values.precompiled_header().empty()) {
-      out->Set(variables::kPrecompiledHeader,
-               RenderValue(values.precompiled_header(), true));
+      out->SetWithoutPathExpansion(
+          variables::kPrecompiledHeader,
+          RenderValue(values.precompiled_header(), true));
     }
     if (what(variables::kPrecompiledSource) &&
         !values.precompiled_source().is_null()) {
-      out->Set(variables::kPrecompiledSource,
-               RenderValue(values.precompiled_source()));
+      out->SetWithoutPathExpansion(variables::kPrecompiledSource,
+                                   RenderValue(values.precompiled_source()));
     }
   }
 
@@ -185,14 +186,14 @@
     const ConfigValues& values = config_->resolved_values();
 
     if (what_.empty())
-      res->SetString(
+      res->SetStringWithoutPathExpansion(
           "toolchain",
           config_->label().GetToolchainLabel().GetUserVisibleName(false));
 
     if (what(variables::kConfigs) && !config_->configs().empty()) {
       auto configs = base::MakeUnique<base::ListValue>();
       FillInConfigVector(configs.get(), config_->configs().vector());
-      res->Set(variables::kConfigs, std::move(configs));
+      res->SetWithoutPathExpansion(variables::kConfigs, std::move(configs));
     }
 
 #define CONFIG_VALUE_ARRAY_HANDLER(name, type)                        \
@@ -200,7 +201,7 @@
     ValuePtr ptr =                                                    \
         render_config_value_array<type>(values, &ConfigValues::name); \
     if (ptr) {                                                        \
-      res->Set(#name, std::move(ptr));                                \
+      res->SetWithoutPathExpansion(#name, std::move(ptr));            \
     }                                                                 \
   }
     CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string)
@@ -258,93 +259,108 @@
     bool is_binary_output = target_->IsBinary();
 
     if (what_.empty()) {
-      res->SetString("type",
-                     Target::GetStringForOutputType(target_->output_type()));
-      res->SetString(
+      res->SetStringWithoutPathExpansion(
+          "type",
+          Target::GetStringForOutputType(target_->output_type()));
+      res->SetStringWithoutPathExpansion(
           "toolchain",
           target_->label().GetToolchainLabel().GetUserVisibleName(false));
     }
 
     // General target meta variables.
     if (what(variables::kVisibility))
-      res->Set(variables::kVisibility, target_->visibility().AsValue());
+      res->SetWithoutPathExpansion(variables::kVisibility,
+                                   target_->visibility().AsValue());
 
     if (what(variables::kTestonly))
-      res->SetBoolean(variables::kTestonly, target_->testonly());
+      res->SetBooleanWithoutPathExpansion(variables::kTestonly,
+                                          target_->testonly());
 
     if (is_binary_output) {
       if (what(variables::kCheckIncludes))
-        res->SetBoolean(variables::kCheckIncludes, target_->check_includes());
+        res->SetBooleanWithoutPathExpansion(variables::kCheckIncludes,
+                                            target_->check_includes());
 
       if (what(variables::kAllowCircularIncludesFrom)) {
         auto labels = base::MakeUnique<base::ListValue>();
         for (const auto& cur : target_->allow_circular_includes_from())
           labels->AppendString(cur.GetUserVisibleName(GetToolchainLabel()));
 
-        res->Set(variables::kAllowCircularIncludesFrom, std::move(labels));
+        res->SetWithoutPathExpansion(variables::kAllowCircularIncludesFrom,
+                                     std::move(labels));
       }
     }
 
     if (what(variables::kSources) && !target_->sources().empty())
-      res->Set(variables::kSources, RenderValue(target_->sources()));
+      res->SetWithoutPathExpansion(variables::kSources,
+                                   RenderValue(target_->sources()));
 
     if (what(variables::kOutputName) && !target_->output_name().empty())
-      res->SetString(variables::kOutputName, target_->output_name());
+      res->SetStringWithoutPathExpansion(variables::kOutputName,
+                                         target_->output_name());
 
     if (what(variables::kOutputDir) && !target_->output_dir().is_null())
-      res->Set(variables::kOutputDir, RenderValue(target_->output_dir()));
+      res->SetWithoutPathExpansion(variables::kOutputDir,
+                                   RenderValue(target_->output_dir()));
 
     if (what(variables::kOutputExtension) && target_->output_extension_set())
-      res->SetString(variables::kOutputExtension, target_->output_extension());
+      res->SetStringWithoutPathExpansion(variables::kOutputExtension,
+                                         target_->output_extension());
 
     if (what(variables::kPublic)) {
       if (target_->all_headers_public())
-        res->SetString(variables::kPublic, "*");
+        res->SetStringWithoutPathExpansion(variables::kPublic, "*");
       else
-        res->Set(variables::kPublic, RenderValue(target_->public_headers()));
+        res->SetWithoutPathExpansion(variables::kPublic,
+                                     RenderValue(target_->public_headers()));
     }
 
     if (what(variables::kInputs) && !target_->inputs().empty())
-      res->Set(variables::kInputs, RenderValue(target_->inputs()));
+      res->SetWithoutPathExpansion(variables::kInputs,
+                                   RenderValue(target_->inputs()));
 
     if (is_binary_output && what(variables::kConfigs) &&
         !target_->configs().empty()) {
       auto configs = base::MakeUnique<base::ListValue>();
       FillInConfigVector(configs.get(), target_->configs().vector());
-      res->Set(variables::kConfigs, std::move(configs));
+      res->SetWithoutPathExpansion(variables::kConfigs, std::move(configs));
     }
 
     if (what(variables::kPublicConfigs) && !target_->public_configs().empty()) {
       auto configs = base::MakeUnique<base::ListValue>();
       FillInConfigVector(configs.get(), target_->public_configs());
-      res->Set(variables::kPublicConfigs, std::move(configs));
+      res->SetWithoutPathExpansion(variables::kPublicConfigs,
+                                   std::move(configs));
     }
 
     if (what(variables::kAllDependentConfigs) &&
         !target_->all_dependent_configs().empty()) {
       auto configs = base::MakeUnique<base::ListValue>();
       FillInConfigVector(configs.get(), target_->all_dependent_configs());
-      res->Set(variables::kAllDependentConfigs, std::move(configs));
+      res->SetWithoutPathExpansion(variables::kAllDependentConfigs,
+                                   std::move(configs));
     }
 
     // Action
     if (target_->output_type() == Target::ACTION ||
         target_->output_type() == Target::ACTION_FOREACH) {
       if (what(variables::kScript))
-        res->SetString(variables::kScript,
-                       target_->action_values().script().value());
+        res->SetStringWithoutPathExpansion(
+            variables::kScript,
+            target_->action_values().script().value());
 
       if (what(variables::kArgs)) {
         auto args = base::MakeUnique<base::ListValue>();
         for (const auto& elem : target_->action_values().args().list())
           args->AppendString(elem.AsString());
 
-        res->Set(variables::kArgs, std::move(args));
+        res->SetWithoutPathExpansion(variables::kArgs, std::move(args));
       }
       if (what(variables::kDepfile) &&
           !target_->action_values().depfile().empty()) {
-        res->SetString(variables::kDepfile,
-                       target_->action_values().depfile().AsString());
+        res->SetStringWithoutPathExpansion(
+            variables::kDepfile,
+            target_->action_values().depfile().AsString());
       }
     }
 
@@ -367,7 +383,7 @@
   if (what(#name)) {                                              \
     ValuePtr ptr = RenderConfigValues<type>(&ConfigValues::name); \
     if (ptr) {                                                    \
-      res->Set(#name, std::move(ptr));                            \
+      res->SetWithoutPathExpansion(#name, std::move(ptr));        \
     }                                                             \
   }
       CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string)
@@ -388,12 +404,12 @@
     }
 
     if (what(variables::kDeps))
-      res->Set(variables::kDeps, RenderDeps());
+      res->SetWithoutPathExpansion(variables::kDeps, RenderDeps());
 
     // Runtime deps are special, print only when explicitly asked for and not in
     // overview mode.
     if (what_.find("runtime_deps") != what_.end())
-      res->Set("runtime_deps", RenderRuntimeDeps());
+      res->SetWithoutPathExpansion("runtime_deps", RenderRuntimeDeps());
 
     // libs and lib_dirs are special in that they're inherited. We don't
     // currently
@@ -408,7 +424,7 @@
         auto libs = base::MakeUnique<base::ListValue>();
         for (size_t i = 0; i < all_libs.size(); i++)
           libs->AppendString(all_libs[i].value());
-        res->Set(variables::kLibs, std::move(libs));
+        res->SetWithoutPathExpansion(variables::kLibs, std::move(libs));
       }
     }
 
@@ -418,7 +434,7 @@
         auto lib_dirs = base::MakeUnique<base::ListValue>();
         for (size_t i = 0; i < all_lib_dirs.size(); i++)
           lib_dirs->AppendString(FormatSourceDir(all_lib_dirs[i]));
-        res->Set(variables::kLibDirs, std::move(lib_dirs));
+        res->SetWithoutPathExpansion(variables::kLibDirs, std::move(lib_dirs));
       }
     }
 
@@ -544,7 +560,7 @@
         dict->SetWithoutPathExpansion(source.value(), std::move(list));
       }
     }
-    res->Set("source_outputs", std::move(dict));
+    res->SetWithoutPathExpansion("source_outputs", std::move(dict));
   }
 
   void FillInBundle(base::DictionaryValue* res) {
@@ -553,21 +569,27 @@
     const Settings* settings = target_->settings();
     BundleData::SourceFiles sources;
     bundle_data.GetSourceFiles(&sources);
-    data->Set("source_files", RenderValue(sources));
-    data->SetString("root_dir_output",
-                    bundle_data.GetBundleRootDirOutput(settings).value());
-    data->Set("root_dir", RenderValue(bundle_data.root_dir()));
-    data->Set("resources_dir", RenderValue(bundle_data.resources_dir()));
-    data->Set("executable_dir", RenderValue(bundle_data.executable_dir()));
-    data->Set("plugins_dir", RenderValue(bundle_data.plugins_dir()));
-    data->SetString("product_type", bundle_data.product_type());
+    data->SetWithoutPathExpansion("source_files", RenderValue(sources));
+    data->SetStringWithoutPathExpansion(
+        "root_dir_output",
+        bundle_data.GetBundleRootDirOutput(settings).value());
+    data->SetWithoutPathExpansion("root_dir",
+                                  RenderValue(bundle_data.root_dir()));
+    data->SetWithoutPathExpansion("resources_dir",
+                                  RenderValue(bundle_data.resources_dir()));
+    data->SetWithoutPathExpansion("executable_dir",
+                                  RenderValue(bundle_data.executable_dir()));
+    data->SetWithoutPathExpansion("plugins_dir",
+                                  RenderValue(bundle_data.plugins_dir()));
+    data->SetStringWithoutPathExpansion("product_type",
+                                        bundle_data.product_type());
 
     auto deps = base::MakeUnique<base::ListValue>();
     for (const auto* dep : bundle_data.bundle_deps())
       deps->AppendString(dep->label().GetUserVisibleName(GetToolchainLabel()));
 
-    data->Set("deps", std::move(deps));
-    res->Set("bundle_data", std::move(data));
+    data->SetWithoutPathExpansion("deps", std::move(deps));
+    res->SetWithoutPathExpansion("bundle_data", std::move(data));
   }
 
   void FillInOutputs(base::DictionaryValue* res) {
@@ -576,12 +598,13 @@
       for (const auto& elem : target_->action_values().outputs().list())
         list->AppendString(elem.AsString());
 
-      res->Set(variables::kOutputs, std::move(list));
+      res->SetWithoutPathExpansion(variables::kOutputs, std::move(list));
     } else if (target_->output_type() == Target::CREATE_BUNDLE) {
       std::vector<SourceFile> output_files;
       target_->bundle_data().GetOutputsAsSourceFiles(target_->settings(),
                                                      &output_files);
-      res->Set(variables::kOutputs, RenderValue(output_files));
+      res->SetWithoutPathExpansion(variables::kOutputs,
+                                   RenderValue(output_files));
     } else if (target_->output_type() == Target::ACTION_FOREACH ||
                target_->output_type() == Target::COPY_FILES) {
       const SubstitutionList& outputs = target_->action_values().outputs();
@@ -590,12 +613,13 @@
         for (const auto& elem : outputs.list())
           patterns->AppendString(elem.AsString());
 
-        res->Set("output_patterns", std::move(patterns));
+        res->SetWithoutPathExpansion("output_patterns", std::move(patterns));
       }
       std::vector<SourceFile> output_files;
       SubstitutionWriter::ApplyListToSources(target_->settings(), outputs,
                                              target_->sources(), &output_files);
-      res->Set(variables::kOutputs, RenderValue(output_files));
+      res->SetWithoutPathExpansion(variables::kOutputs,
+                                   RenderValue(output_files));
     } else {
       DCHECK(target_->IsBinary());
       const Tool* tool =
@@ -609,7 +633,8 @@
         output_files_as_source_file.push_back(
             output_file.AsSourceFile(target_->settings()->build_settings()));
 
-      res->Set(variables::kOutputs, RenderValue(output_files_as_source_file));
+      res->SetWithoutPathExpansion(variables::kOutputs,
+                                   RenderValue(output_files_as_source_file));
     }
   }
 
diff --git a/tools/gn/json_project_writer.cc b/tools/gn/json_project_writer.cc
index 67c21ee..44576cd 100644
--- a/tools/gn/json_project_writer.cc
+++ b/tools/gn/json_project_writer.cc
@@ -100,19 +100,23 @@
         !outputs_value->empty()) {
       description->MergeDictionary(outputs.get());
     }
-    targets->Set(target->label().GetUserVisibleName(default_toolchain_label),
-                 std::move(description));
+    targets->SetWithoutPathExpansion(
+        target->label().GetUserVisibleName(default_toolchain_label),
+        std::move(description));
   }
 
   auto settings = base::MakeUnique<base::DictionaryValue>();
-  settings->SetString("root_path", build_settings->root_path_utf8());
-  settings->SetString("build_dir", build_settings->build_dir().value());
-  settings->SetString("default_toolchain",
-                      default_toolchain_label.GetUserVisibleName(false));
+  settings->SetStringWithoutPathExpansion("root_path",
+                                          build_settings->root_path_utf8());
+  settings->SetStringWithoutPathExpansion("build_dir",
+                                          build_settings->build_dir().value());
+  settings->SetStringWithoutPathExpansion(
+      "default_toolchain",
+      default_toolchain_label.GetUserVisibleName(false));
 
   auto output = base::MakeUnique<base::DictionaryValue>();
-  output->Set("targets", std::move(targets));
-  output->Set("build_settings", std::move(settings));
+  output->SetWithoutPathExpansion("targets", std::move(targets));
+  output->SetWithoutPathExpansion("build_settings", std::move(settings));
 
   std::string s;
   base::JSONWriter::WriteWithOptions(