GN: Print the import trail when parse errors occur.

This is especially useful when asserts fail when the file should not be
included in the first place.

Example error message:
ERROR at //build/config/android/internal_rules.gni:11:1: Assertion failed.
assert(false)
^-----
See //build/config/android/rules.gni:7:1: whence it was imported.
import("//build/config/android/internal_rules.gni")
^-------------------------------------------------
See //media/midi/BUILD.gn:13:3: whence it was imported.
  import("//build/config/android/rules.gni")
  ^----------------------------------------
See //BUILD.gn:193:7: which caused the package to be included.
      "//media/midi:midi_unittests",
      ^----------------------------

BUG=604972

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

Cr-Original-Commit-Position: refs/heads/master@{#388986}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: dbecf02976975b93db37c3b5e3aa26d6fc92c517
diff --git a/tools/gn/import_manager.cc b/tools/gn/import_manager.cc
index 8c57008..86cfd45 100644
--- a/tools/gn/import_manager.cc
+++ b/tools/gn/import_manager.cc
@@ -30,8 +30,12 @@
 
   scope->SetProcessingImport();
   node->Execute(scope.get(), err);
-  if (err->has_error())
+  if (err->has_error()) {
+    // If there was an error, append the caller location so the error message
+    // displays a why the file was imported (esp. useful for failed asserts).
+    err->AppendSubErr(Err(node_for_err, "whence it was imported."));
     return nullptr;
+  }
   scope->ClearProcessingImport();
 
   return scope;
diff --git a/tools/gn/loader.cc b/tools/gn/loader.cc
index 3ac868c..e3165b9 100644
--- a/tools/gn/loader.cc
+++ b/tools/gn/loader.cc
@@ -211,7 +211,7 @@
   pending_loads_++;
   if (!AsyncLoadFile(origin, settings->build_settings(), file,
                      base::Bind(&LoaderImpl::BackgroundLoadFile, this,
-                                settings, file),
+                                settings, file, origin),
                      &err)) {
     g_scheduler->FailWithError(err);
     DecrementPendingLoads();
@@ -235,6 +235,7 @@
 
 void LoaderImpl::BackgroundLoadFile(const Settings* settings,
                                     const SourceFile& file_name,
+                                    const LocationRange& origin,
                                     const ParseNode* root) {
   if (!root) {
     main_loop_->PostTask(FROM_HERE,
@@ -260,11 +261,15 @@
 
   Err err;
   root->Execute(&our_scope, &err);
-  if (err.has_error())
-    g_scheduler->FailWithError(err);
+  if (!err.has_error())
+    our_scope.CheckForUnusedVars(&err);
 
-  if (!our_scope.CheckForUnusedVars(&err))
+  if (err.has_error()) {
+    if (!origin.is_null())
+      err.AppendSubErr(Err(origin, "which caused the file to be included."));
     g_scheduler->FailWithError(err);
+  }
+
 
   // Pass all of the items that were defined off to the builder.
   for (auto& item : collected_items) {
diff --git a/tools/gn/loader.h b/tools/gn/loader.h
index 37f7085..a610835 100644
--- a/tools/gn/loader.h
+++ b/tools/gn/loader.h
@@ -129,6 +129,7 @@
   // input file manager.
   void BackgroundLoadFile(const Settings* settings,
                           const SourceFile& file_name,
+                          const LocationRange& origin,
                           const ParseNode* root);
   void BackgroundLoadBuildConfig(
       Settings* settings,
diff --git a/tools/gn/location.h b/tools/gn/location.h
index 44d1a6f..647c6f7 100644
--- a/tools/gn/location.h
+++ b/tools/gn/location.h
@@ -19,6 +19,7 @@
   int line_number() const { return line_number_; }
   int column_number() const { return column_number_; }
   int byte() const { return byte_; }
+  bool is_null() const { return *this == Location(); }
 
   bool operator==(const Location& other) const;
   bool operator!=(const Location& other) const;
@@ -45,6 +46,10 @@
 
   const Location& begin() const { return begin_; }
   const Location& end() const { return end_; }
+  bool is_null() const {
+    return begin_.is_null();  // No need to check both for the null case.
+  }
+
 
   LocationRange Union(const LocationRange& other) const;