• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "tools/gn/import_manager.h"
6 
7 #include "base/memory/scoped_ptr.h"
8 #include "base/stl_util.h"
9 #include "tools/gn/parse_tree.h"
10 #include "tools/gn/scheduler.h"
11 #include "tools/gn/scope_per_file_provider.h"
12 
13 namespace {
14 
15 // Returns a newly-allocated scope on success, null on failure.
UncachedImport(const Settings * settings,const SourceFile & file,const ParseNode * node_for_err,Err * err)16 Scope* UncachedImport(const Settings* settings,
17                       const SourceFile& file,
18                       const ParseNode* node_for_err,
19                       Err* err) {
20   const ParseNode* node = g_scheduler->input_file_manager()->SyncLoadFile(
21       node_for_err->GetRange(), settings->build_settings(), file, err);
22   if (!node)
23     return NULL;
24   const BlockNode* block = node->AsBlock();
25   CHECK(block);
26 
27   scoped_ptr<Scope> scope(new Scope(settings->base_config()));
28   scope->set_source_dir(file.GetDir());
29 
30   // Don't allow ScopePerFileProvider to provide target-related variables.
31   // These will be relative to the imported file, which is probably not what
32   // people mean when they use these.
33   ScopePerFileProvider per_file_provider(scope.get(), false);
34 
35   scope->SetProcessingImport();
36   block->ExecuteBlockInScope(scope.get(), err);
37   if (err->has_error())
38     return NULL;
39   scope->ClearProcessingImport();
40 
41   return scope.release();
42 }
43 
44 }  // namesapce
45 
ImportManager()46 ImportManager::ImportManager() {
47 }
48 
~ImportManager()49 ImportManager::~ImportManager() {
50   STLDeleteContainerPairSecondPointers(imports_.begin(), imports_.end());
51 }
52 
DoImport(const SourceFile & file,const ParseNode * node_for_err,Scope * scope,Err * err)53 bool ImportManager::DoImport(const SourceFile& file,
54                              const ParseNode* node_for_err,
55                              Scope* scope,
56                              Err* err) {
57   // See if we have a cached import, but be careful to actually do the scope
58   // copying outside of the lock.
59   const Scope* imported_scope = NULL;
60   {
61     base::AutoLock lock(lock_);
62     ImportMap::const_iterator found = imports_.find(file);
63     if (found != imports_.end())
64       imported_scope = found->second;
65   }
66 
67   if (!imported_scope) {
68     // Do a new import of the file.
69     imported_scope = UncachedImport(scope->settings(), file,
70                                     node_for_err, err);
71     if (!imported_scope)
72       return false;
73 
74     // We loaded the file outside the lock. This means that there could be a
75     // race and the file was already loaded on a background thread. Recover
76     // from this and use the existing one if that happens.
77     {
78       base::AutoLock lock(lock_);
79       ImportMap::const_iterator found = imports_.find(file);
80       if (found != imports_.end()) {
81         delete imported_scope;
82         imported_scope = found->second;
83       } else {
84         imports_[file] = imported_scope;
85       }
86     }
87   }
88 
89   Scope::MergeOptions options;
90   options.skip_private_vars = true;
91   options.mark_used = true;  // Don't require all imported values be used.
92   return imported_scope->NonRecursiveMergeTo(scope, options, node_for_err,
93                                              "import", err);
94 }
95