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