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"
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;
21 Scope::Scope(const Settings* settings)
22 : const_containing_(NULL),
23 mutable_containing_(NULL),
26 item_collector_(NULL) {
29 Scope::Scope(Scope* parent)
30 : const_containing_(NULL),
31 mutable_containing_(parent),
32 settings_(parent->settings()),
34 item_collector_(NULL) {
37 Scope::Scope(const Scope* parent)
38 : const_containing_(parent),
39 mutable_containing_(NULL),
40 settings_(parent->settings()),
42 item_collector_(NULL) {
46 STLDeleteContainerPairSecondPointers(target_defaults_.begin(),
47 target_defaults_.end());
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);
60 RecordMap::iterator found = values_.find(ident);
61 if (found != values_.end()) {
63 found->second.used = true;
64 return &found->second.value;
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);
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()) {
81 found->second.used = true;
82 return &found->second.value;
85 // Search in the parent mutable scope, but not const one.
86 if (mutable_containing_)
87 return mutable_containing_->GetMutableValue(ident, counts_as_used);
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.
97 // Search in the parent scope.
99 const Value* in_containing = containing()->GetValue(ident);
101 // Promote to current scope.
102 return SetValue(ident, *in_containing, set_node);
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;
113 return containing()->GetValue(ident);
117 Value* Scope::SetValue(const base::StringPiece& ident,
119 const ParseNode* set_node) {
120 Record& r = values_[ident]; // Clears any existing value.
122 r.value.set_origin(set_node);
126 bool Scope::AddTemplate(const std::string& name, const Template* templ) {
127 if (GetTemplate(name))
129 templates_[name] = templ;
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();
138 return containing()->GetTemplate(name);
142 void Scope::MarkUsed(const base::StringPiece& ident) {
143 RecordMap::iterator found = values_.find(ident);
144 if (found == values_.end()) {
148 found->second.used = true;
151 void Scope::MarkUnused(const base::StringPiece& ident) {
152 RecordMap::iterator found = values_.find(ident);
153 if (found == values_.end()) {
157 found->second.used = false;
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) {
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.";
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.",
183 // This will happen for internally-generated variables.
184 *err = Err(i->second.value.origin(), "Assignment had no effect.", help);
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;
197 bool Scope::NonRecursiveMergeTo(Scope* dest,
198 bool clobber_existing,
199 const ParseNode* node_for_err,
200 const char* desc_for_err,
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() +
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."));
221 dest->values_[i->first] = i->second;
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
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.");
243 // Be careful to delete any pointer we're about to clobber.
244 Scope** dest_scope = &dest->target_defaults_[i->first];
247 *dest_scope = new Scope(settings_);
248 i->second->NonRecursiveMergeTo(*dest_scope, clobber_existing, node_for_err,
249 "<SHOULDN'T HAPPEN>", err);
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.");
264 dest->sources_assignment_filter_.reset(
265 new PatternList(*sources_assignment_filter_));
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 \"" +
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(),
283 "Executing " + desc_string + " should not conflict with anything "
284 "in the current\nscope."));
289 // Be careful to delete any pointer we're about to clobber.
290 dest->templates_[i->first] = i->second;
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
305 result = mutable_containing_->MakeClosure();
307 // This is a standalone scope, just copy it.
308 result.reset(new Scope(settings_));
311 // Add in our variables and we're done.
313 NonRecursiveMergeTo(result.get(), true, NULL, "<SHOULDN'T HAPPEN>", &err);
314 DCHECK(!err.has_error());
315 return result.Pass();
318 Scope* Scope::MakeTargetDefaults(const std::string& target_type) {
319 if (GetTargetDefaults(target_type))
322 Scope** dest = &target_defaults_[target_type];
324 NOTREACHED(); // Already set.
327 *dest = new Scope(settings_);
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;
336 return containing()->GetTargetDefaults(target_type);
340 const PatternList* Scope::GetSourcesAssignmentFilter() const {
341 if (sources_assignment_filter_)
342 return sources_assignment_filter_.get();
344 return containing()->GetSourcesAssignmentFilter();
348 void Scope::SetProcessingBuildConfig() {
349 DCHECK((mode_flags_ & kProcessingBuildConfigFlag) == 0);
350 mode_flags_ |= kProcessingBuildConfigFlag;
353 void Scope::ClearProcessingBuildConfig() {
354 DCHECK(mode_flags_ & kProcessingBuildConfigFlag);
355 mode_flags_ &= ~(kProcessingBuildConfigFlag);
358 bool Scope::IsProcessingBuildConfig() const {
359 if (mode_flags_ & kProcessingBuildConfigFlag)
362 return containing()->IsProcessingBuildConfig();
366 void Scope::SetProcessingImport() {
367 DCHECK((mode_flags_ & kProcessingImportFlag) == 0);
368 mode_flags_ |= kProcessingImportFlag;
371 void Scope::ClearProcessingImport() {
372 DCHECK(mode_flags_ & kProcessingImportFlag);
373 mode_flags_ &= ~(kProcessingImportFlag);
376 bool Scope::IsProcessingImport() const {
377 if (mode_flags_ & kProcessingImportFlag)
380 return containing()->IsProcessingImport();
384 const SourceDir& Scope::GetSourceDir() const {
385 if (!source_dir_.is_null())
388 return containing()->GetSourceDir();
392 Scope::ItemVector* Scope::GetItemCollector() {
394 return item_collector_;
395 if (mutable_containing())
396 return mutable_containing()->GetItemCollector();
400 void Scope::SetProperty(const void* key, void* value) {
402 DCHECK(properties_.find(key) != properties_.end());
403 properties_.erase(key);
405 properties_[key] = value;
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()) {
413 *found_on_scope = this;
414 return found->second;
417 return containing()->GetProperty(key, found_on_scope);
421 void Scope::AddProvider(ProgrammaticProvider* p) {
422 programmatic_providers_.insert(p);
425 void Scope::RemoveProvider(ProgrammaticProvider* p) {
426 DCHECK(programmatic_providers_.find(p) != programmatic_providers_.end());
427 programmatic_providers_.erase(p);