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;
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] == '_';
28 Scope::Scope(const Settings
* settings
)
29 : const_containing_(NULL
),
30 mutable_containing_(NULL
),
33 item_collector_(NULL
) {
36 Scope::Scope(Scope
* parent
)
37 : const_containing_(NULL
),
38 mutable_containing_(parent
),
39 settings_(parent
->settings()),
41 item_collector_(NULL
) {
44 Scope::Scope(const Scope
* parent
)
45 : const_containing_(parent
),
46 mutable_containing_(NULL
),
47 settings_(parent
->settings()),
49 item_collector_(NULL
) {
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
);
67 RecordMap::iterator found
= values_
.find(ident
);
68 if (found
!= values_
.end()) {
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
);
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()) {
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
);
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.
106 const Value
* in_containing
= containing()->GetValue(ident
);
108 // Promote to current scope.
109 return SetValue(ident
, *in_containing
, set_node
);
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
;
120 return containing()->GetValue(ident
);
124 Value
* Scope::SetValue(const base::StringPiece
& ident
,
126 const ParseNode
* set_node
) {
127 Record
& r
= values_
[ident
]; // Clears any existing value.
129 r
.value
.set_origin(set_node
);
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
))
157 templates_
[name
] = templ
;
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();
166 return containing()->GetTemplate(name
);
170 void Scope::MarkUsed(const base::StringPiece
& ident
) {
171 RecordMap::iterator found
= values_
.find(ident
);
172 if (found
== values_
.end()) {
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()) {
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
) {
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.",
211 // This will happen for internally-generated variables.
212 *err
= Err(i
->second
.value
.origin(), "Assignment had no effect.", help
);
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
,
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() +
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."));
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
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.");
277 // Be careful to delete any pointer we're about to clobber.
278 Scope
** dest_scope
= &dest
->target_defaults_
[i
->first
];
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.");
298 dest
->sources_assignment_filter_
.reset(
299 new PatternList(*sources_assignment_filter_
));
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 \"" +
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(),
320 "Executing " + desc_string
+ " should not conflict with anything "
321 "in the current\nscope."));
326 // Be careful to delete any pointer we're about to clobber.
327 dest
->templates_
[i
->first
] = i
->second
;
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
342 result
= mutable_containing_
->MakeClosure();
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.
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
))
364 Scope
** dest
= &target_defaults_
[target_type
];
366 NOTREACHED(); // Already set.
369 *dest
= new Scope(settings_
);
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
;
378 return containing()->GetTargetDefaults(target_type
);
382 const PatternList
* Scope::GetSourcesAssignmentFilter() const {
383 if (sources_assignment_filter_
)
384 return sources_assignment_filter_
.get();
386 return containing()->GetSourcesAssignmentFilter();
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
)
404 return containing()->IsProcessingBuildConfig();
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
)
422 return containing()->IsProcessingImport();
426 const SourceDir
& Scope::GetSourceDir() const {
427 if (!source_dir_
.is_null())
430 return containing()->GetSourceDir();
434 Scope::ItemVector
* Scope::GetItemCollector() {
436 return item_collector_
;
437 if (mutable_containing())
438 return mutable_containing()->GetItemCollector();
442 void Scope::SetProperty(const void* key
, void* value
) {
444 DCHECK(properties_
.find(key
) != properties_
.end());
445 properties_
.erase(key
);
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()) {
455 *found_on_scope
= this;
456 return found
->second
;
459 return containing()->GetProperty(key
, found_on_scope
);
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
);