Fix breaking change in It2me Host on Ozone
[chromium-blink-merge.git] / tools / gn / scope.cc
blobcd5bd604f37fc466c06d30be15defe15e4d60ed5
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_(nullptr),
30 mutable_containing_(nullptr),
31 settings_(settings),
32 mode_flags_(0),
33 item_collector_(nullptr) {
36 Scope::Scope(Scope* parent)
37 : const_containing_(nullptr),
38 mutable_containing_(parent),
39 settings_(parent->settings()),
40 mode_flags_(0),
41 item_collector_(nullptr) {
44 Scope::Scope(const Scope* parent)
45 : const_containing_(parent),
46 mutable_containing_(nullptr),
47 settings_(parent->settings()),
48 mode_flags_(0),
49 item_collector_(nullptr) {
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 (const auto& provider : programmatic_providers_) {
61 const Value* v = provider->GetProgrammaticValue(ident);
62 if (v)
63 return v;
66 RecordMap::iterator found = values_.find(ident);
67 if (found != values_.end()) {
68 if (counts_as_used)
69 found->second.used = true;
70 return &found->second.value;
73 // Search in the parent scope.
74 if (const_containing_)
75 return const_containing_->GetValue(ident);
76 if (mutable_containing_)
77 return mutable_containing_->GetValue(ident, counts_as_used);
78 return nullptr;
81 Value* Scope::GetMutableValue(const base::StringPiece& ident,
82 bool counts_as_used) {
83 // Don't do programatic values, which are not mutable.
84 RecordMap::iterator found = values_.find(ident);
85 if (found != values_.end()) {
86 if (counts_as_used)
87 found->second.used = true;
88 return &found->second.value;
91 // Search in the parent mutable scope, but not const one.
92 if (mutable_containing_)
93 return mutable_containing_->GetMutableValue(ident, counts_as_used);
94 return nullptr;
97 Value* Scope::GetValueForcedToCurrentScope(const base::StringPiece& ident,
98 const ParseNode* set_node) {
99 RecordMap::iterator found = values_.find(ident);
100 if (found != values_.end())
101 return &found->second.value; // Already have in the current scope.
103 // Search in the parent scope.
104 if (containing()) {
105 const Value* in_containing = containing()->GetValue(ident);
106 if (in_containing) {
107 // Promote to current scope.
108 return SetValue(ident, *in_containing, set_node);
111 return nullptr;
114 const Value* Scope::GetValue(const base::StringPiece& ident) const {
115 RecordMap::const_iterator found = values_.find(ident);
116 if (found != values_.end())
117 return &found->second.value;
118 if (containing())
119 return containing()->GetValue(ident);
120 return nullptr;
123 Value* Scope::SetValue(const base::StringPiece& ident,
124 const Value& v,
125 const ParseNode* set_node) {
126 Record& r = values_[ident]; // Clears any existing value.
127 r.value = v;
128 r.value.set_origin(set_node);
129 return &r.value;
132 void Scope::RemoveIdentifier(const base::StringPiece& ident) {
133 RecordMap::iterator found = values_.find(ident);
134 if (found != values_.end())
135 values_.erase(found);
138 void Scope::RemovePrivateIdentifiers() {
139 // Do it in two phases to avoid mutating while iterating. Our hash map is
140 // currently backed by several different vendor-specific implementations and
141 // I'm not sure if all of them support mutating while iterating. Since this
142 // is not perf-critical, do the safe thing.
143 std::vector<base::StringPiece> to_remove;
144 for (const auto& cur : values_) {
145 if (IsPrivateVar(cur.first))
146 to_remove.push_back(cur.first);
149 for (const auto& cur : to_remove)
150 values_.erase(cur);
153 bool Scope::AddTemplate(const std::string& name, const Template* templ) {
154 if (GetTemplate(name))
155 return false;
156 templates_[name] = templ;
157 return true;
160 const Template* Scope::GetTemplate(const std::string& name) const {
161 TemplateMap::const_iterator found = templates_.find(name);
162 if (found != templates_.end())
163 return found->second.get();
164 if (containing())
165 return containing()->GetTemplate(name);
166 return nullptr;
169 void Scope::MarkUsed(const base::StringPiece& ident) {
170 RecordMap::iterator found = values_.find(ident);
171 if (found == values_.end()) {
172 NOTREACHED();
173 return;
175 found->second.used = true;
178 void Scope::MarkUnused(const base::StringPiece& ident) {
179 RecordMap::iterator found = values_.find(ident);
180 if (found == values_.end()) {
181 NOTREACHED();
182 return;
184 found->second.used = false;
187 bool Scope::IsSetButUnused(const base::StringPiece& ident) const {
188 RecordMap::const_iterator found = values_.find(ident);
189 if (found != values_.end()) {
190 if (!found->second.used) {
191 return true;
194 return false;
197 bool Scope::CheckForUnusedVars(Err* err) const {
198 for (const auto& pair : values_) {
199 if (!pair.second.used) {
200 std::string help = "You set the variable \"" + pair.first.as_string() +
201 "\" here and it was unused before it went\nout of scope.";
203 const BinaryOpNode* binary = pair.second.value.origin()->AsBinaryOp();
204 if (binary && binary->op().type() == Token::EQUAL) {
205 // Make a nicer error message for normal var sets.
206 *err = Err(binary->left()->GetRange(), "Assignment had no effect.",
207 help);
208 } else {
209 // This will happen for internally-generated variables.
210 *err = Err(pair.second.value.origin(), "Assignment had no effect.",
211 help);
213 return false;
216 return true;
219 void Scope::GetCurrentScopeValues(KeyValueMap* output) const {
220 for (const auto& pair : values_)
221 (*output)[pair.first] = pair.second.value;
224 bool Scope::NonRecursiveMergeTo(Scope* dest,
225 const MergeOptions& options,
226 const ParseNode* node_for_err,
227 const char* desc_for_err,
228 Err* err) const {
229 // Values.
230 for (const auto& pair : values_) {
231 if (options.skip_private_vars && IsPrivateVar(pair.first))
232 continue; // Skip this private var.
234 const Value& new_value = pair.second.value;
235 if (!options.clobber_existing) {
236 const Value* existing_value = dest->GetValue(pair.first);
237 if (existing_value && new_value != *existing_value) {
238 // Value present in both the source and the dest.
239 std::string desc_string(desc_for_err);
240 *err = Err(node_for_err, "Value collision.",
241 "This " + desc_string + " contains \"" + pair.first.as_string() +
242 "\"");
243 err->AppendSubErr(Err(pair.second.value, "defined here.",
244 "Which would clobber the one in your current scope"));
245 err->AppendSubErr(Err(*existing_value, "defined here.",
246 "Executing " + desc_string + " should not conflict with anything "
247 "in the current\nscope unless the values are identical."));
248 return false;
251 dest->values_[pair.first] = pair.second;
253 if (options.mark_used)
254 dest->MarkUsed(pair.first);
257 // Target defaults are owning pointers.
258 for (const auto& pair : target_defaults_) {
259 if (!options.clobber_existing) {
260 if (dest->GetTargetDefaults(pair.first)) {
261 // TODO(brettw) it would be nice to know the origin of a
262 // set_target_defaults so we can give locations for the colliding target
263 // defaults.
264 std::string desc_string(desc_for_err);
265 *err = Err(node_for_err, "Target defaults collision.",
266 "This " + desc_string + " contains target defaults for\n"
267 "\"" + pair.first + "\" which would clobber one for the\n"
268 "same target type in your current scope. It's unfortunate that I'm "
269 "too stupid\nto tell you the location of where the target defaults "
270 "were set. Usually\nthis happens in the BUILDCONFIG.gn file.");
271 return false;
275 // Be careful to delete any pointer we're about to clobber.
276 Scope** dest_scope = &dest->target_defaults_[pair.first];
277 if (*dest_scope)
278 delete *dest_scope;
279 *dest_scope = new Scope(settings_);
280 pair.second->NonRecursiveMergeTo(*dest_scope, options, node_for_err,
281 "<SHOULDN'T HAPPEN>", err);
284 // Sources assignment filter.
285 if (sources_assignment_filter_) {
286 if (!options.clobber_existing) {
287 if (dest->GetSourcesAssignmentFilter()) {
288 // Sources assignment filter present in both the source and the dest.
289 std::string desc_string(desc_for_err);
290 *err = Err(node_for_err, "Assignment filter collision.",
291 "The " + desc_string + " contains a sources_assignment_filter "
292 "which\nwould clobber the one in your current scope.");
293 return false;
296 dest->sources_assignment_filter_.reset(
297 new PatternList(*sources_assignment_filter_));
300 // Templates.
301 for (const auto& pair : templates_) {
302 if (options.skip_private_vars && IsPrivateVar(pair.first))
303 continue; // Skip this private template.
305 if (!options.clobber_existing) {
306 const Template* existing_template = dest->GetTemplate(pair.first);
307 // Since templates are refcounted, we can check if it's the same one by
308 // comparing pointers.
309 if (existing_template && pair.second.get() != existing_template) {
310 // Rule present in both the source and the dest, and they're not the
311 // same one.
312 std::string desc_string(desc_for_err);
313 *err = Err(node_for_err, "Template collision.",
314 "This " + desc_string + " contains a template \"" +
315 pair.first + "\"");
316 err->AppendSubErr(Err(pair.second->GetDefinitionRange(),
317 "defined here.",
318 "Which would clobber the one in your current scope"));
319 err->AppendSubErr(Err(existing_template->GetDefinitionRange(),
320 "defined here.",
321 "Executing " + desc_string + " should not conflict with anything "
322 "in the current\nscope."));
323 return false;
327 // Be careful to delete any pointer we're about to clobber.
328 dest->templates_[pair.first] = pair.second;
331 return true;
334 scoped_ptr<Scope> Scope::MakeClosure() const {
335 scoped_ptr<Scope> result;
336 if (const_containing_) {
337 // We reached the top of the mutable scope stack. The result scope just
338 // references the const scope (which will never change).
339 result.reset(new Scope(const_containing_));
340 } else if (mutable_containing_) {
341 // There are more nested mutable scopes. Recursively go up the stack to
342 // get the closure.
343 result = mutable_containing_->MakeClosure();
344 } else {
345 // This is a standalone scope, just copy it.
346 result.reset(new Scope(settings_));
349 // Want to clobber since we've flattened some nested scopes, and our parent
350 // scope may have a duplicate value set.
351 MergeOptions options;
352 options.clobber_existing = true;
354 // Add in our variables and we're done.
355 Err err;
356 NonRecursiveMergeTo(result.get(), options, nullptr, "<SHOULDN'T HAPPEN>",
357 &err);
358 DCHECK(!err.has_error());
359 return result.Pass();
362 Scope* Scope::MakeTargetDefaults(const std::string& target_type) {
363 if (GetTargetDefaults(target_type))
364 return nullptr;
366 Scope** dest = &target_defaults_[target_type];
367 if (*dest) {
368 NOTREACHED(); // Already set.
369 return *dest;
371 *dest = new Scope(settings_);
372 return *dest;
375 const Scope* Scope::GetTargetDefaults(const std::string& target_type) const {
376 NamedScopeMap::const_iterator found = target_defaults_.find(target_type);
377 if (found != target_defaults_.end())
378 return found->second;
379 if (containing())
380 return containing()->GetTargetDefaults(target_type);
381 return nullptr;
384 const PatternList* Scope::GetSourcesAssignmentFilter() const {
385 if (sources_assignment_filter_)
386 return sources_assignment_filter_.get();
387 if (containing())
388 return containing()->GetSourcesAssignmentFilter();
389 return nullptr;
392 void Scope::SetProcessingBuildConfig() {
393 DCHECK((mode_flags_ & kProcessingBuildConfigFlag) == 0);
394 mode_flags_ |= kProcessingBuildConfigFlag;
397 void Scope::ClearProcessingBuildConfig() {
398 DCHECK(mode_flags_ & kProcessingBuildConfigFlag);
399 mode_flags_ &= ~(kProcessingBuildConfigFlag);
402 bool Scope::IsProcessingBuildConfig() const {
403 if (mode_flags_ & kProcessingBuildConfigFlag)
404 return true;
405 if (containing())
406 return containing()->IsProcessingBuildConfig();
407 return false;
410 void Scope::SetProcessingImport() {
411 DCHECK((mode_flags_ & kProcessingImportFlag) == 0);
412 mode_flags_ |= kProcessingImportFlag;
415 void Scope::ClearProcessingImport() {
416 DCHECK(mode_flags_ & kProcessingImportFlag);
417 mode_flags_ &= ~(kProcessingImportFlag);
420 bool Scope::IsProcessingImport() const {
421 if (mode_flags_ & kProcessingImportFlag)
422 return true;
423 if (containing())
424 return containing()->IsProcessingImport();
425 return false;
428 const SourceDir& Scope::GetSourceDir() const {
429 if (!source_dir_.is_null())
430 return source_dir_;
431 if (containing())
432 return containing()->GetSourceDir();
433 return source_dir_;
436 Scope::ItemVector* Scope::GetItemCollector() {
437 if (item_collector_)
438 return item_collector_;
439 if (mutable_containing())
440 return mutable_containing()->GetItemCollector();
441 return nullptr;
444 void Scope::SetProperty(const void* key, void* value) {
445 if (!value) {
446 DCHECK(properties_.find(key) != properties_.end());
447 properties_.erase(key);
448 } else {
449 properties_[key] = value;
453 void* Scope::GetProperty(const void* key, const Scope** found_on_scope) const {
454 PropertyMap::const_iterator found = properties_.find(key);
455 if (found != properties_.end()) {
456 if (found_on_scope)
457 *found_on_scope = this;
458 return found->second;
460 if (containing())
461 return containing()->GetProperty(key, found_on_scope);
462 return nullptr;
465 void Scope::AddProvider(ProgrammaticProvider* p) {
466 programmatic_providers_.insert(p);
469 void Scope::RemoveProvider(ProgrammaticProvider* p) {
470 DCHECK(programmatic_providers_.find(p) != programmatic_providers_.end());
471 programmatic_providers_.erase(p);