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