• 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/scope.h"
6 
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "tools/gn/parse_tree.h"
10 #include "tools/gn/template.h"
11 
12 namespace {
13 
14 // FLags set in the mode_flags_ of a scope. If a bit is set, it applies
15 // recursively to all dependent scopes.
16 const unsigned kProcessingBuildConfigFlag = 1;
17 const unsigned kProcessingImportFlag = 2;
18 
19 // Returns true if this variable name should be considered private. Private
20 // values start with an underscore, and are not imported from "gni" files
21 // when processing an import.
IsPrivateVar(const base::StringPiece & name)22 bool IsPrivateVar(const base::StringPiece& name) {
23   return name.empty() || name[0] == '_';
24 }
25 
26 }  // namespace
27 
Scope(const Settings * settings)28 Scope::Scope(const Settings* settings)
29     : const_containing_(NULL),
30       mutable_containing_(NULL),
31       settings_(settings),
32       mode_flags_(0),
33       item_collector_(NULL) {
34 }
35 
Scope(Scope * parent)36 Scope::Scope(Scope* parent)
37     : const_containing_(NULL),
38       mutable_containing_(parent),
39       settings_(parent->settings()),
40       mode_flags_(0),
41       item_collector_(NULL) {
42 }
43 
Scope(const Scope * parent)44 Scope::Scope(const Scope* parent)
45     : const_containing_(parent),
46       mutable_containing_(NULL),
47       settings_(parent->settings()),
48       mode_flags_(0),
49       item_collector_(NULL) {
50 }
51 
~Scope()52 Scope::~Scope() {
53   STLDeleteContainerPairSecondPointers(target_defaults_.begin(),
54                                        target_defaults_.end());
55 }
56 
GetValue(const base::StringPiece & ident,bool counts_as_used)57 const Value* Scope::GetValue(const base::StringPiece& ident,
58                              bool counts_as_used) {
59   // First check for programatically-provided values.
60   for (ProviderSet::const_iterator i = programmatic_providers_.begin();
61        i != programmatic_providers_.end(); ++i) {
62     const Value* v = (*i)->GetProgrammaticValue(ident);
63     if (v)
64       return v;
65   }
66 
67   RecordMap::iterator found = values_.find(ident);
68   if (found != values_.end()) {
69     if (counts_as_used)
70       found->second.used = true;
71     return &found->second.value;
72   }
73 
74   // Search in the parent scope.
75   if (const_containing_)
76     return const_containing_->GetValue(ident);
77   if (mutable_containing_)
78     return mutable_containing_->GetValue(ident, counts_as_used);
79   return NULL;
80 }
81 
GetMutableValue(const base::StringPiece & ident,bool counts_as_used)82 Value* Scope::GetMutableValue(const base::StringPiece& ident,
83                               bool counts_as_used) {
84   // Don't do programatic values, which are not mutable.
85   RecordMap::iterator found = values_.find(ident);
86   if (found != values_.end()) {
87     if (counts_as_used)
88       found->second.used = true;
89     return &found->second.value;
90   }
91 
92   // Search in the parent mutable scope, but not const one.
93   if (mutable_containing_)
94     return mutable_containing_->GetMutableValue(ident, counts_as_used);
95   return NULL;
96 }
97 
GetValueForcedToCurrentScope(const base::StringPiece & ident,const ParseNode * set_node)98 Value* Scope::GetValueForcedToCurrentScope(const base::StringPiece& ident,
99                                            const ParseNode* set_node) {
100   RecordMap::iterator found = values_.find(ident);
101   if (found != values_.end())
102     return &found->second.value;  // Already have in the current scope.
103 
104   // Search in the parent scope.
105   if (containing()) {
106     const Value* in_containing = containing()->GetValue(ident);
107     if (in_containing) {
108       // Promote to current scope.
109       return SetValue(ident, *in_containing, set_node);
110     }
111   }
112   return NULL;
113 }
114 
GetValue(const base::StringPiece & ident) const115 const Value* Scope::GetValue(const base::StringPiece& ident) const {
116   RecordMap::const_iterator found = values_.find(ident);
117   if (found != values_.end())
118     return &found->second.value;
119   if (containing())
120     return containing()->GetValue(ident);
121   return NULL;
122 }
123 
SetValue(const base::StringPiece & ident,const Value & v,const ParseNode * set_node)124 Value* Scope::SetValue(const base::StringPiece& ident,
125                        const Value& v,
126                        const ParseNode* set_node) {
127   Record& r = values_[ident];  // Clears any existing value.
128   r.value = v;
129   r.value.set_origin(set_node);
130   return &r.value;
131 }
132 
RemoveIdentifier(const base::StringPiece & ident)133 void Scope::RemoveIdentifier(const base::StringPiece& ident) {
134   RecordMap::iterator found = values_.find(ident);
135   if (found != values_.end())
136     values_.erase(found);
137 }
138 
RemovePrivateIdentifiers()139 void Scope::RemovePrivateIdentifiers() {
140   // Do it in two phases to avoid mutating while iterating. Our hash map is
141   // currently backed by several different vendor-specific implementations and
142   // I'm not sure if all of them support mutating while iterating. Since this
143   // is not perf-critical, do the safe thing.
144   std::vector<base::StringPiece> to_remove;
145   for (RecordMap::const_iterator i = values_.begin(); i != values_.end(); ++i) {
146     if (IsPrivateVar(i->first))
147       to_remove.push_back(i->first);
148   }
149 
150   for (size_t i = 0; i < to_remove.size(); i++)
151     values_.erase(to_remove[i]);
152 }
153 
AddTemplate(const std::string & name,const Template * templ)154 bool Scope::AddTemplate(const std::string& name, const Template* templ) {
155   if (GetTemplate(name))
156     return false;
157   templates_[name] = templ;
158   return true;
159 }
160 
GetTemplate(const std::string & name) const161 const Template* Scope::GetTemplate(const std::string& name) const {
162   TemplateMap::const_iterator found = templates_.find(name);
163   if (found != templates_.end())
164     return found->second.get();
165   if (containing())
166     return containing()->GetTemplate(name);
167   return NULL;
168 }
169 
MarkUsed(const base::StringPiece & ident)170 void Scope::MarkUsed(const base::StringPiece& ident) {
171   RecordMap::iterator found = values_.find(ident);
172   if (found == values_.end()) {
173     NOTREACHED();
174     return;
175   }
176   found->second.used = true;
177 }
178 
MarkUnused(const base::StringPiece & ident)179 void Scope::MarkUnused(const base::StringPiece& ident) {
180   RecordMap::iterator found = values_.find(ident);
181   if (found == values_.end()) {
182     NOTREACHED();
183     return;
184   }
185   found->second.used = false;
186 }
187 
IsSetButUnused(const base::StringPiece & ident) const188 bool Scope::IsSetButUnused(const base::StringPiece& ident) const {
189   RecordMap::const_iterator found = values_.find(ident);
190   if (found != values_.end()) {
191     if (!found->second.used) {
192       return true;
193     }
194   }
195   return false;
196 }
197 
CheckForUnusedVars(Err * err) const198 bool Scope::CheckForUnusedVars(Err* err) const {
199   for (RecordMap::const_iterator i = values_.begin();
200        i != values_.end(); ++i) {
201     if (!i->second.used) {
202       std::string help = "You set the variable \"" + i->first.as_string() +
203           "\" here and it was unused before it went\nout of scope.";
204 
205       const BinaryOpNode* binary = i->second.value.origin()->AsBinaryOp();
206       if (binary && binary->op().type() == Token::EQUAL) {
207         // Make a nicer error message for normal var sets.
208         *err = Err(binary->left()->GetRange(), "Assignment had no effect.",
209                    help);
210       } else {
211         // This will happen for internally-generated variables.
212         *err = Err(i->second.value.origin(), "Assignment had no effect.", help);
213       }
214       return false;
215     }
216   }
217   return true;
218 }
219 
GetCurrentScopeValues(KeyValueMap * output) const220 void Scope::GetCurrentScopeValues(KeyValueMap* output) const {
221   for (RecordMap::const_iterator i = values_.begin(); i != values_.end(); ++i)
222     (*output)[i->first] = i->second.value;
223 }
224 
NonRecursiveMergeTo(Scope * dest,const MergeOptions & options,const ParseNode * node_for_err,const char * desc_for_err,Err * err) const225 bool Scope::NonRecursiveMergeTo(Scope* dest,
226                                 const MergeOptions& options,
227                                 const ParseNode* node_for_err,
228                                 const char* desc_for_err,
229                                 Err* err) const {
230   // Values.
231   for (RecordMap::const_iterator i = values_.begin(); i != values_.end(); ++i) {
232     if (options.skip_private_vars && IsPrivateVar(i->first))
233       continue;  // Skip this private var.
234 
235     const Value& new_value = i->second.value;
236     if (!options.clobber_existing) {
237       const Value* existing_value = dest->GetValue(i->first);
238       if (existing_value && new_value != *existing_value) {
239         // Value present in both the source and the dest.
240         std::string desc_string(desc_for_err);
241         *err = Err(node_for_err, "Value collision.",
242             "This " + desc_string + " contains \"" + i->first.as_string() +
243             "\"");
244         err->AppendSubErr(Err(i->second.value, "defined here.",
245             "Which would clobber the one in your current scope"));
246         err->AppendSubErr(Err(*existing_value, "defined here.",
247             "Executing " + desc_string + " should not conflict with anything "
248             "in the current\nscope unless the values are identical."));
249         return false;
250       }
251     }
252     dest->values_[i->first] = i->second;
253 
254     if (options.mark_used)
255       dest->MarkUsed(i->first);
256   }
257 
258   // Target defaults are owning pointers.
259   for (NamedScopeMap::const_iterator i = target_defaults_.begin();
260        i != target_defaults_.end(); ++i) {
261     if (!options.clobber_existing) {
262       if (dest->GetTargetDefaults(i->first)) {
263         // TODO(brettw) it would be nice to know the origin of a
264         // set_target_defaults so we can give locations for the colliding target
265         // defaults.
266         std::string desc_string(desc_for_err);
267         *err = Err(node_for_err, "Target defaults collision.",
268             "This " + desc_string + " contains target defaults for\n"
269             "\"" + i->first + "\" which would clobber one for the\n"
270             "same target type in your current scope. It's unfortunate that I'm "
271             "too stupid\nto tell you the location of where the target defaults "
272             "were set. Usually\nthis happens in the BUILDCONFIG.gn file.");
273         return false;
274       }
275     }
276 
277     // Be careful to delete any pointer we're about to clobber.
278     Scope** dest_scope = &dest->target_defaults_[i->first];
279     if (*dest_scope)
280       delete *dest_scope;
281     *dest_scope = new Scope(settings_);
282     i->second->NonRecursiveMergeTo(*dest_scope, options, node_for_err,
283                                    "<SHOULDN'T HAPPEN>", err);
284   }
285 
286   // Sources assignment filter.
287   if (sources_assignment_filter_) {
288     if (!options.clobber_existing) {
289       if (dest->GetSourcesAssignmentFilter()) {
290         // Sources assignment filter present in both the source and the dest.
291         std::string desc_string(desc_for_err);
292         *err = Err(node_for_err, "Assignment filter collision.",
293             "The " + desc_string + " contains a sources_assignment_filter "
294             "which\nwould clobber the one in your current scope.");
295         return false;
296       }
297     }
298     dest->sources_assignment_filter_.reset(
299         new PatternList(*sources_assignment_filter_));
300   }
301 
302   // Templates.
303   for (TemplateMap::const_iterator i = templates_.begin();
304        i != templates_.end(); ++i) {
305     if (options.skip_private_vars && IsPrivateVar(i->first))
306       continue;  // Skip this private template.
307 
308     if (!options.clobber_existing) {
309       const Template* existing_template = dest->GetTemplate(i->first);
310       // Since templates are refcounted, we can check if it's the same one by
311       // comparing pointers.
312       if (existing_template && i->second.get() != existing_template) {
313         // Rule present in both the source and the dest, and they're not the
314         // same one.
315         std::string desc_string(desc_for_err);
316         *err = Err(node_for_err, "Template collision.",
317             "This " + desc_string + " contains a template \"" +
318             i->first + "\"");
319         err->AppendSubErr(Err(i->second->GetDefinitionRange(), "defined here.",
320             "Which would clobber the one in your current scope"));
321         err->AppendSubErr(Err(existing_template->GetDefinitionRange(),
322             "defined here.",
323             "Executing " + desc_string + " should not conflict with anything "
324             "in the current\nscope."));
325         return false;
326       }
327     }
328 
329     // Be careful to delete any pointer we're about to clobber.
330     dest->templates_[i->first] = i->second;
331   }
332 
333   return true;
334 }
335 
MakeClosure() const336 scoped_ptr<Scope> Scope::MakeClosure() const {
337   scoped_ptr<Scope> result;
338   if (const_containing_) {
339     // We reached the top of the mutable scope stack. The result scope just
340     // references the const scope (which will never change).
341     result.reset(new Scope(const_containing_));
342   } else if (mutable_containing_) {
343     // There are more nested mutable scopes. Recursively go up the stack to
344     // get the closure.
345     result = mutable_containing_->MakeClosure();
346   } else {
347     // This is a standalone scope, just copy it.
348     result.reset(new Scope(settings_));
349   }
350 
351   // Want to clobber since we've flattened some nested scopes, and our parent
352   // scope may have a duplicate value set.
353   MergeOptions options;
354   options.clobber_existing = true;
355 
356   // Add in our variables and we're done.
357   Err err;
358   NonRecursiveMergeTo(result.get(), options, NULL, "<SHOULDN'T HAPPEN>", &err);
359   DCHECK(!err.has_error());
360   return result.Pass();
361 }
362 
MakeTargetDefaults(const std::string & target_type)363 Scope* Scope::MakeTargetDefaults(const std::string& target_type) {
364   if (GetTargetDefaults(target_type))
365     return NULL;
366 
367   Scope** dest = &target_defaults_[target_type];
368   if (*dest) {
369     NOTREACHED();  // Already set.
370     return *dest;
371   }
372   *dest = new Scope(settings_);
373   return *dest;
374 }
375 
GetTargetDefaults(const std::string & target_type) const376 const Scope* Scope::GetTargetDefaults(const std::string& target_type) const {
377   NamedScopeMap::const_iterator found = target_defaults_.find(target_type);
378   if (found != target_defaults_.end())
379     return found->second;
380   if (containing())
381     return containing()->GetTargetDefaults(target_type);
382   return NULL;
383 }
384 
GetSourcesAssignmentFilter() const385 const PatternList* Scope::GetSourcesAssignmentFilter() const {
386   if (sources_assignment_filter_)
387     return sources_assignment_filter_.get();
388   if (containing())
389     return containing()->GetSourcesAssignmentFilter();
390   return NULL;
391 }
392 
SetProcessingBuildConfig()393 void Scope::SetProcessingBuildConfig() {
394   DCHECK((mode_flags_ & kProcessingBuildConfigFlag) == 0);
395   mode_flags_ |= kProcessingBuildConfigFlag;
396 }
397 
ClearProcessingBuildConfig()398 void Scope::ClearProcessingBuildConfig() {
399   DCHECK(mode_flags_ & kProcessingBuildConfigFlag);
400   mode_flags_ &= ~(kProcessingBuildConfigFlag);
401 }
402 
IsProcessingBuildConfig() const403 bool Scope::IsProcessingBuildConfig() const {
404   if (mode_flags_ & kProcessingBuildConfigFlag)
405     return true;
406   if (containing())
407     return containing()->IsProcessingBuildConfig();
408   return false;
409 }
410 
SetProcessingImport()411 void Scope::SetProcessingImport() {
412   DCHECK((mode_flags_ & kProcessingImportFlag) == 0);
413   mode_flags_ |= kProcessingImportFlag;
414 }
415 
ClearProcessingImport()416 void Scope::ClearProcessingImport() {
417   DCHECK(mode_flags_ & kProcessingImportFlag);
418   mode_flags_ &= ~(kProcessingImportFlag);
419 }
420 
IsProcessingImport() const421 bool Scope::IsProcessingImport() const {
422   if (mode_flags_ & kProcessingImportFlag)
423     return true;
424   if (containing())
425     return containing()->IsProcessingImport();
426   return false;
427 }
428 
GetSourceDir() const429 const SourceDir& Scope::GetSourceDir() const {
430   if (!source_dir_.is_null())
431     return source_dir_;
432   if (containing())
433     return containing()->GetSourceDir();
434   return source_dir_;
435 }
436 
GetItemCollector()437 Scope::ItemVector* Scope::GetItemCollector() {
438   if (item_collector_)
439     return item_collector_;
440   if (mutable_containing())
441     return mutable_containing()->GetItemCollector();
442   return NULL;
443 }
444 
SetProperty(const void * key,void * value)445 void Scope::SetProperty(const void* key, void* value) {
446   if (!value) {
447     DCHECK(properties_.find(key) != properties_.end());
448     properties_.erase(key);
449   } else {
450     properties_[key] = value;
451   }
452 }
453 
GetProperty(const void * key,const Scope ** found_on_scope) const454 void* Scope::GetProperty(const void* key, const Scope** found_on_scope) const {
455   PropertyMap::const_iterator found = properties_.find(key);
456   if (found != properties_.end()) {
457     if (found_on_scope)
458       *found_on_scope = this;
459     return found->second;
460   }
461   if (containing())
462     return containing()->GetProperty(key, found_on_scope);
463   return NULL;
464 }
465 
AddProvider(ProgrammaticProvider * p)466 void Scope::AddProvider(ProgrammaticProvider* p) {
467   programmatic_providers_.insert(p);
468 }
469 
RemoveProvider(ProgrammaticProvider * p)470 void Scope::RemoveProvider(ProgrammaticProvider* p) {
471   DCHECK(programmatic_providers_.find(p) != programmatic_providers_.end());
472   programmatic_providers_.erase(p);
473 }
474