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),
28 Scope::Scope(Scope* parent)
29 : const_containing_(NULL),
30 mutable_containing_(parent),
31 settings_(parent->settings()),
35 Scope::Scope(const Scope* parent)
36 : const_containing_(parent),
37 mutable_containing_(NULL),
38 settings_(parent->settings()),
43 STLDeleteContainerPairSecondPointers(target_defaults_.begin(),
44 target_defaults_.end());
45 STLDeleteContainerPairSecondPointers(templates_.begin(), templates_.end());
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);
58 RecordMap::iterator found = values_.find(ident);
59 if (found != values_.end()) {
61 found->second.used = true;
62 return &found->second.value;
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);
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()) {
79 found->second.used = true;
80 return &found->second.value;
83 // Search in the parent mutable scope, but not const one.
84 if (mutable_containing_)
85 return mutable_containing_->GetMutableValue(ident, counts_as_used);
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.
95 // Search in the parent scope.
97 const Value* in_containing = containing()->GetValue(ident);
99 // Promote to current scope.
100 return SetValue(ident, *in_containing, set_node);
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;
111 return containing()->GetValue(ident);
115 Value* Scope::SetValue(const base::StringPiece& ident,
117 const ParseNode* set_node) {
118 Record& r = values_[ident]; // Clears any existing value.
120 r.value.set_origin(set_node);
124 bool Scope::AddTemplate(const std::string& name, scoped_ptr<Template> templ) {
125 if (GetTemplate(name))
127 templates_[name] = templ.release();
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;
136 return containing()->GetTemplate(name);
140 void Scope::MarkUsed(const base::StringPiece& ident) {
141 RecordMap::iterator found = values_.find(ident);
142 if (found == values_.end()) {
146 found->second.used = true;
149 void Scope::MarkUnused(const base::StringPiece& ident) {
150 RecordMap::iterator found = values_.find(ident);
151 if (found == values_.end()) {
155 found->second.used = false;
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) {
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.";
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.",
181 // This will happen for internally-generated variables.
182 *err = Err(i->second.value.origin(), "Assignment had no effect.", help);
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;
195 bool Scope::NonRecursiveMergeTo(Scope* dest,
196 bool clobber_existing,
197 const ParseNode* node_for_err,
198 const char* desc_for_err,
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() +
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."));
219 dest->values_[i->first] = i->second;
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
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.");
241 // Be careful to delete any pointer we're about to clobber.
242 Scope** dest_scope = &dest->target_defaults_[i->first];
245 *dest_scope = new Scope(settings_);
246 i->second->NonRecursiveMergeTo(*dest_scope, clobber_existing, node_for_err,
247 "<SHOULDN'T HAPPEN>", err);
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.");
262 dest->sources_assignment_filter_.reset(
263 new PatternList(*sources_assignment_filter_));
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 \"" +
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(),
281 "Executing " + desc_string + " should not conflict with anything "
282 "in the current\nscope."));
287 // Be careful to delete any pointer we're about to clobber.
288 const Template** dest_template = &dest->templates_[i->first];
290 delete *dest_template;
291 *dest_template = i->second;
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
306 result = mutable_containing_->MakeClosure();
308 // This is a standalone scope, just copy it.
309 result.reset(new Scope(settings_));
312 // Add in our variables and we're done.
314 NonRecursiveMergeTo(result.get(), true, NULL, "<SHOULDN'T HAPPEN>", &err);
315 DCHECK(!err.has_error());
316 return result.Pass();
319 Scope* Scope::MakeTargetDefaults(const std::string& target_type) {
320 if (GetTargetDefaults(target_type))
323 Scope** dest = &target_defaults_[target_type];
325 NOTREACHED(); // Already set.
328 *dest = new Scope(settings_);
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;
337 return containing()->GetTargetDefaults(target_type);
341 const PatternList* Scope::GetSourcesAssignmentFilter() const {
342 if (sources_assignment_filter_)
343 return sources_assignment_filter_.get();
345 return containing()->GetSourcesAssignmentFilter();
349 void Scope::SetProcessingBuildConfig() {
350 DCHECK((mode_flags_ & kProcessingBuildConfigFlag) == 0);
351 mode_flags_ |= kProcessingBuildConfigFlag;
354 void Scope::ClearProcessingBuildConfig() {
355 DCHECK(mode_flags_ & kProcessingBuildConfigFlag);
356 mode_flags_ &= ~(kProcessingBuildConfigFlag);
359 bool Scope::IsProcessingBuildConfig() const {
360 if (mode_flags_ & kProcessingBuildConfigFlag)
363 return containing()->IsProcessingBuildConfig();
367 void Scope::SetProcessingImport() {
368 DCHECK((mode_flags_ & kProcessingImportFlag) == 0);
369 mode_flags_ |= kProcessingImportFlag;
372 void Scope::ClearProcessingImport() {
373 DCHECK(mode_flags_ & kProcessingImportFlag);
374 mode_flags_ &= ~(kProcessingImportFlag);
377 bool Scope::IsProcessingImport() const {
378 if (mode_flags_ & kProcessingImportFlag)
381 return containing()->IsProcessingImport();
385 const SourceDir& Scope::GetSourceDir() const {
386 if (!source_dir_.is_null())
389 return containing()->GetSourceDir();
393 void Scope::SetProperty(const void* key, void* value) {
395 DCHECK(properties_.find(key) != properties_.end());
396 properties_.erase(key);
398 properties_[key] = value;
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()) {
406 *found_on_scope = this;
407 return found->second;
410 return containing()->GetProperty(key, found_on_scope);
414 void Scope::AddProvider(ProgrammaticProvider* p) {
415 programmatic_providers_.insert(p);
418 void Scope::RemoveProvider(ProgrammaticProvider* p) {
419 DCHECK(programmatic_providers_.find(p) != programmatic_providers_.end());
420 programmatic_providers_.erase(p);