GN: Schedule config loads for sub-configs.

Previously the Builder did not schedule file loads for configs of configs.

This meant that if a BUILD file contained only configs referenced by other
configs (rather than configs referenced by targets, or targets referenced by
other targets), it would never be loaded. The result will be a failed run with
an undefined object.

BUG=536844

Review URL: https://codereview.chromium.org/1373903002

Cr-Original-Commit-Position: refs/heads/master@{#351089}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 1b1e7e8c8f3105b6c9811ff28947961eb96153c3
diff --git a/tools/gn/builder.cc b/tools/gn/builder.cc
index fbd4d57..3a0c1f5 100644
--- a/tools/gn/builder.cc
+++ b/tools/gn/builder.cc
@@ -240,6 +240,17 @@
   Config* config = record->item()->AsConfig();
   if (!AddDeps(record, config->configs(), err))
     return false;
+
+  // Make sure all deps of this config are scheduled to be loaded. For other
+  // item types like targets, the "should generate" flag is propogated around
+  // to mark whether this should happen. We could call
+  // RecursiveSetShouldGenerate to do this step here, but since configs nor
+  // anything they depend on is actually written, the "generate" flag isn't
+  // relevant and means extra book keeping. Just force load any deps of this
+  // config.
+  for (const auto& cur : record->all_deps())
+    ScheduleItemLoadIfNecessary(cur);
+
   return true;
 }
 
diff --git a/tools/gn/builder_unittest.cc b/tools/gn/builder_unittest.cc
index ffd1a9d..a5356a2 100644
--- a/tools/gn/builder_unittest.cc
+++ b/tools/gn/builder_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "tools/gn/builder.h"
+#include "tools/gn/config.h"
 #include "tools/gn/loader.h"
 #include "tools/gn/target.h"
 #include "tools/gn/test_with_scope.h"
@@ -32,8 +33,17 @@
     return files_.empty();
   }
 
-  // Returns true if two loads have been requested and they match the given
-  // file. This will clear the records so it will be empty for the next call.
+  // Returns true if one/two loads have been requested and they match the given
+  // file(s). This will clear the records so it will be empty for the next call.
+  bool HasLoadedOne(const SourceFile& file) {
+    if (files_.size() != 1u) {
+      files_.clear();
+      return false;
+    }
+    bool match = (files_[0] == file);
+    files_.clear();
+    return match;
+  }
   bool HasLoadedTwo(const SourceFile& a, const SourceFile& b) {
     if (files_.size() != 2u) {
       files_.clear();
@@ -216,3 +226,24 @@
   // It should have gotten pushed to B.
   EXPECT_TRUE(b_record->should_generate());
 }
+
+// Tests that configs applied to a config get loaded (bug 536844).
+TEST_F(BuilderTest, ConfigLoad) {
+  SourceDir toolchain_dir = settings_.toolchain_label().dir();
+  std::string toolchain_name = settings_.toolchain_label().name();
+
+  // Construct a dependency chain: A -> B -> C. Define A first with a
+  // forward-reference to B, then C, then B to test the different orders that
+  // the dependencies are hooked up.
+  Label a_label(SourceDir("//a/"), "a", toolchain_dir, toolchain_name);
+  Label b_label(SourceDir("//b/"), "b", toolchain_dir, toolchain_name);
+  Label c_label(SourceDir("//c/"), "c", toolchain_dir, toolchain_name);
+
+  // The builder will take ownership of the pointers.
+  Config* a = new Config(&settings_, a_label);
+  a->configs().push_back(LabelConfigPair(b_label));
+  builder_->ItemDefined(scoped_ptr<Item>(a));
+
+  // Should have requested that B is loaded.
+  EXPECT_TRUE(loader_->HasLoadedOne(SourceFile("//b/BUILD.gn")));
+}