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