Fix click-to-play positioning.
[chromium-blink-merge.git] / tools / gn / scope.cc
blob4e049ebbc545ad997de936ffd37ffdaca7197967
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.
5 #include "tools/gn/scope.h"
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "tools/gn/parse_tree.h"
10 #include "tools/gn/template.h"
12 namespace {
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;
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.
22 bool IsPrivateVar(const base::StringPiece& name) {
23 return name.empty() || name[0] == '_';
26 } // namespace
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) {
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) {
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) {
52 Scope::~Scope() {
53 STLDeleteContainerPairSecondPointers(target_defaults_.begin(),
54 target_defaults_.end());
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;
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;
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;
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;
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;
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.
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);
112 return NULL;
115 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;
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;
133 void Scope::RemoveIdentifier(const base::StringPiece& ident) {
134 RecordMap::iterator found = values_.find(ident);
135 if (found != values_.end())
136 values_.erase(found);
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);
150 for (size_t i = 0; i < to_remove.size(); i++)
151 values_.erase(to_remove[i]);
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;
161 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;
170 void Scope::MarkUsed(const base::StringPiece& ident) {
171 RecordMap::iterator found = values_.find(ident);
172 if (found == values_.end()) {
173 NOTREACHED();
174 return;
176 found->second.used = true;
179 void Scope::MarkUnused(const base::StringPiece& ident) {
180 RecordMap::iterator found = values_.find(ident);
181 if (found == values_.end()) {
182 NOTREACHED();
183 return;
185 found->second.used = false;
188 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;
195 return false;
198 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.";
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);
214 return false;
217 return true;
220 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;
225 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.
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;
252 dest->values_[i->first] = i->second;
254 if (options.mark_used)
255 dest->MarkUsed(i->first);
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;
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);
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;
298 dest->sources_assignment_filter_.reset(
299 new PatternList(*sources_assignment_filter_));
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.
308 if (!options.clobber_existing) {
309 const Template* existing_template = dest->GetTemplate(i->first);
310 if (existing_template) {
311 // Rule present in both the source and the dest.
312 std::string desc_string(desc_for_err);
313 *err = Err(node_for_err, "Template collision.",
314 "This " + desc_string + " contains a template \"" +
315 i->first + "\"");
316 err->AppendSubErr(Err(i->second->GetDefinitionRange(), "defined here.",
317 "Which would clobber the one in your current scope"));
318 err->AppendSubErr(Err(existing_template->GetDefinitionRange(),
319 "defined here.",
320 "Executing " + desc_string + " should not conflict with anything "
321 "in the current\nscope."));
322 return false;
326 // Be careful to delete any pointer we're about to clobber.
327 dest->templates_[i->first] = i->second;
330 return true;
333 scoped_ptr<Scope> Scope::MakeClosure() const {
334 scoped_ptr<Scope> result;
335 if (const_containing_) {
336 // We reached the top of the mutable scope stack. The result scope just
337 // references the const scope (which will never change).
338 result.reset(new Scope(const_containing_));
339 } else if (mutable_containing_) {
340 // There are more nested mutable scopes. Recursively go up the stack to
341 // get the closure.
342 result = mutable_containing_->MakeClosure();
343 } else {
344 // This is a standalone scope, just copy it.
345 result.reset(new Scope(settings_));
348 // Want to clobber since we've flattened some nested scopes, and our parent
349 // scope may have a duplicate value set.
350 MergeOptions options;
351 options.clobber_existing = true;
353 // Add in our variables and we're done.
354 Err err;
355 NonRecursiveMergeTo(result.get(), options, NULL, "<SHOULDN'T HAPPEN>", &err);
356 DCHECK(!err.has_error());
357 return result.Pass();
360 Scope* Scope::MakeTargetDefaults(const std::string& target_type) {
361 if (GetTargetDefaults(target_type))
362 return NULL;
364 Scope** dest = &target_defaults_[target_type];
365 if (*dest) {
366 NOTREACHED(); // Already set.
367 return *dest;
369 *dest = new Scope(settings_);
370 return *dest;
373 const Scope* Scope::GetTargetDefaults(const std::string& target_type) const {
374 NamedScopeMap::const_iterator found = target_defaults_.find(target_type);
375 if (found != target_defaults_.end())
376 return found->second;
377 if (containing())
378 return containing()->GetTargetDefaults(target_type);
379 return NULL;
382 const PatternList* Scope::GetSourcesAssignmentFilter() const {
383 if (sources_assignment_filter_)
384 return sources_assignment_filter_.get();
385 if (containing())
386 return containing()->GetSourcesAssignmentFilter();
387 return NULL;
390 void Scope::SetProcessingBuildConfig() {
391 DCHECK((mode_flags_ & kProcessingBuildConfigFlag) == 0);
392 mode_flags_ |= kProcessingBuildConfigFlag;
395 void Scope::ClearProcessingBuildConfig() {
396 DCHECK(mode_flags_ & kProcessingBuildConfigFlag);
397 mode_flags_ &= ~(kProcessingBuildConfigFlag);
400 bool Scope::IsProcessingBuildConfig() const {
401 if (mode_flags_ & kProcessingBuildConfigFlag)
402 return true;
403 if (containing())
404 return containing()->IsProcessingBuildConfig();
405 return false;
408 void Scope::SetProcessingImport() {
409 DCHECK((mode_flags_ & kProcessingImportFlag) == 0);
410 mode_flags_ |= kProcessingImportFlag;
413 void Scope::ClearProcessingImport() {
414 DCHECK(mode_flags_ & kProcessingImportFlag);
415 mode_flags_ &= ~(kProcessingImportFlag);
418 bool Scope::IsProcessingImport() const {
419 if (mode_flags_ & kProcessingImportFlag)
420 return true;
421 if (containing())
422 return containing()->IsProcessingImport();
423 return false;
426 const SourceDir& Scope::GetSourceDir() const {
427 if (!source_dir_.is_null())
428 return source_dir_;
429 if (containing())
430 return containing()->GetSourceDir();
431 return source_dir_;
434 Scope::ItemVector* Scope::GetItemCollector() {
435 if (item_collector_)
436 return item_collector_;
437 if (mutable_containing())
438 return mutable_containing()->GetItemCollector();
439 return NULL;
442 void Scope::SetProperty(const void* key, void* value) {
443 if (!value) {
444 DCHECK(properties_.find(key) != properties_.end());
445 properties_.erase(key);
446 } else {
447 properties_[key] = value;
451 void* Scope::GetProperty(const void* key, const Scope** found_on_scope) const {
452 PropertyMap::const_iterator found = properties_.find(key);
453 if (found != properties_.end()) {
454 if (found_on_scope)
455 *found_on_scope = this;
456 return found->second;
458 if (containing())
459 return containing()->GetProperty(key, found_on_scope);
460 return NULL;
463 void Scope::AddProvider(ProgrammaticProvider* p) {
464 programmatic_providers_.insert(p);
467 void Scope::RemoveProvider(ProgrammaticProvider* p) {
468 DCHECK(programmatic_providers_.find(p) != programmatic_providers_.end());
469 programmatic_providers_.erase(p);