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] == '_';
29 Scope::ProgrammaticProvider::~ProgrammaticProvider() {
30 scope_
->RemoveProvider(this);
33 Scope::Scope(const Settings
* settings
)
34 : const_containing_(nullptr),
35 mutable_containing_(nullptr),
38 item_collector_(nullptr) {
41 Scope::Scope(Scope
* parent
)
42 : const_containing_(nullptr),
43 mutable_containing_(parent
),
44 settings_(parent
->settings()),
46 item_collector_(nullptr) {
49 Scope::Scope(const Scope
* parent
)
50 : const_containing_(parent
),
51 mutable_containing_(nullptr),
52 settings_(parent
->settings()),
54 item_collector_(nullptr) {
58 STLDeleteContainerPairSecondPointers(target_defaults_
.begin(),
59 target_defaults_
.end());
62 const Value
* Scope::GetValue(const base::StringPiece
& ident
,
63 bool counts_as_used
) {
64 // First check for programmatically-provided values.
65 for (const auto& provider
: programmatic_providers_
) {
66 const Value
* v
= provider
->GetProgrammaticValue(ident
);
71 RecordMap::iterator found
= values_
.find(ident
);
72 if (found
!= values_
.end()) {
74 found
->second
.used
= true;
75 return &found
->second
.value
;
78 // Search in the parent scope.
79 if (const_containing_
)
80 return const_containing_
->GetValue(ident
);
81 if (mutable_containing_
)
82 return mutable_containing_
->GetValue(ident
, counts_as_used
);
86 Value
* Scope::GetMutableValue(const base::StringPiece
& ident
,
87 bool counts_as_used
) {
88 // Don't do programmatic values, which are not mutable.
89 RecordMap::iterator found
= values_
.find(ident
);
90 if (found
!= values_
.end()) {
92 found
->second
.used
= true;
93 return &found
->second
.value
;
96 // Search in the parent mutable scope, but not const one.
97 if (mutable_containing_
)
98 return mutable_containing_
->GetMutableValue(ident
, counts_as_used
);
102 Value
* Scope::GetValueForcedToCurrentScope(const base::StringPiece
& ident
,
103 const ParseNode
* set_node
) {
104 RecordMap::iterator found
= values_
.find(ident
);
105 if (found
!= values_
.end())
106 return &found
->second
.value
; // Already have in the current scope.
108 // Search in the parent scope.
110 const Value
* in_containing
= containing()->GetValue(ident
);
112 // Promote to current scope.
113 return SetValue(ident
, *in_containing
, set_node
);
119 base::StringPiece
Scope::GetStorageKey(const base::StringPiece
& ident
) const {
120 RecordMap::const_iterator found
= values_
.find(ident
);
121 if (found
!= values_
.end())
124 // Search in parent scope.
126 return containing()->GetStorageKey(ident
);
127 return base::StringPiece();
130 const Value
* Scope::GetValue(const base::StringPiece
& ident
) const {
131 RecordMap::const_iterator found
= values_
.find(ident
);
132 if (found
!= values_
.end())
133 return &found
->second
.value
;
135 return containing()->GetValue(ident
);
139 Value
* Scope::SetValue(const base::StringPiece
& ident
,
141 const ParseNode
* set_node
) {
142 Record
& r
= values_
[ident
]; // Clears any existing value.
144 r
.value
.set_origin(set_node
);
148 void Scope::RemoveIdentifier(const base::StringPiece
& ident
) {
149 RecordMap::iterator found
= values_
.find(ident
);
150 if (found
!= values_
.end())
151 values_
.erase(found
);
154 void Scope::RemovePrivateIdentifiers() {
155 // Do it in two phases to avoid mutating while iterating. Our hash map is
156 // currently backed by several different vendor-specific implementations and
157 // I'm not sure if all of them support mutating while iterating. Since this
158 // is not perf-critical, do the safe thing.
159 std::vector
<base::StringPiece
> to_remove
;
160 for (const auto& cur
: values_
) {
161 if (IsPrivateVar(cur
.first
))
162 to_remove
.push_back(cur
.first
);
165 for (const auto& cur
: to_remove
)
169 bool Scope::AddTemplate(const std::string
& name
, const Template
* templ
) {
170 if (GetTemplate(name
))
172 templates_
[name
] = templ
;
176 const Template
* Scope::GetTemplate(const std::string
& name
) const {
177 TemplateMap::const_iterator found
= templates_
.find(name
);
178 if (found
!= templates_
.end())
179 return found
->second
.get();
181 return containing()->GetTemplate(name
);
185 void Scope::MarkUsed(const base::StringPiece
& ident
) {
186 RecordMap::iterator found
= values_
.find(ident
);
187 if (found
== values_
.end()) {
191 found
->second
.used
= true;
194 void Scope::MarkAllUsed() {
195 for (auto& cur
: values_
)
196 cur
.second
.used
= true;
199 void Scope::MarkUnused(const base::StringPiece
& ident
) {
200 RecordMap::iterator found
= values_
.find(ident
);
201 if (found
== values_
.end()) {
205 found
->second
.used
= false;
208 bool Scope::IsSetButUnused(const base::StringPiece
& ident
) const {
209 RecordMap::const_iterator found
= values_
.find(ident
);
210 if (found
!= values_
.end()) {
211 if (!found
->second
.used
) {
218 bool Scope::CheckForUnusedVars(Err
* err
) const {
219 for (const auto& pair
: values_
) {
220 if (!pair
.second
.used
) {
221 std::string help
= "You set the variable \"" + pair
.first
.as_string() +
222 "\" here and it was unused before it went\nout of scope.";
224 const BinaryOpNode
* binary
= pair
.second
.value
.origin()->AsBinaryOp();
225 if (binary
&& binary
->op().type() == Token::EQUAL
) {
226 // Make a nicer error message for normal var sets.
227 *err
= Err(binary
->left()->GetRange(), "Assignment had no effect.",
230 // This will happen for internally-generated variables.
231 *err
= Err(pair
.second
.value
.origin(), "Assignment had no effect.",
240 void Scope::GetCurrentScopeValues(KeyValueMap
* output
) const {
241 for (const auto& pair
: values_
)
242 (*output
)[pair
.first
] = pair
.second
.value
;
245 bool Scope::NonRecursiveMergeTo(Scope
* dest
,
246 const MergeOptions
& options
,
247 const ParseNode
* node_for_err
,
248 const char* desc_for_err
,
251 for (const auto& pair
: values_
) {
252 if (options
.skip_private_vars
&& IsPrivateVar(pair
.first
))
253 continue; // Skip this private var.
255 const Value
& new_value
= pair
.second
.value
;
256 if (!options
.clobber_existing
) {
257 const Value
* existing_value
= dest
->GetValue(pair
.first
);
258 if (existing_value
&& new_value
!= *existing_value
) {
259 // Value present in both the source and the dest.
260 std::string
desc_string(desc_for_err
);
261 *err
= Err(node_for_err
, "Value collision.",
262 "This " + desc_string
+ " contains \"" + pair
.first
.as_string() +
264 err
->AppendSubErr(Err(pair
.second
.value
, "defined here.",
265 "Which would clobber the one in your current scope"));
266 err
->AppendSubErr(Err(*existing_value
, "defined here.",
267 "Executing " + desc_string
+ " should not conflict with anything "
268 "in the current\nscope unless the values are identical."));
272 dest
->values_
[pair
.first
] = pair
.second
;
274 if (options
.mark_dest_used
)
275 dest
->MarkUsed(pair
.first
);
278 // Target defaults are owning pointers.
279 for (const auto& pair
: target_defaults_
) {
280 if (!options
.clobber_existing
) {
281 if (dest
->GetTargetDefaults(pair
.first
)) {
282 // TODO(brettw) it would be nice to know the origin of a
283 // set_target_defaults so we can give locations for the colliding target
285 std::string
desc_string(desc_for_err
);
286 *err
= Err(node_for_err
, "Target defaults collision.",
287 "This " + desc_string
+ " contains target defaults for\n"
288 "\"" + pair
.first
+ "\" which would clobber one for the\n"
289 "same target type in your current scope. It's unfortunate that I'm "
290 "too stupid\nto tell you the location of where the target defaults "
291 "were set. Usually\nthis happens in the BUILDCONFIG.gn file.");
296 // Be careful to delete any pointer we're about to clobber.
297 Scope
** dest_scope
= &dest
->target_defaults_
[pair
.first
];
300 *dest_scope
= new Scope(settings_
);
301 pair
.second
->NonRecursiveMergeTo(*dest_scope
, options
, node_for_err
,
302 "<SHOULDN'T HAPPEN>", err
);
305 // Sources assignment filter.
306 if (sources_assignment_filter_
) {
307 if (!options
.clobber_existing
) {
308 if (dest
->GetSourcesAssignmentFilter()) {
309 // Sources assignment filter present in both the source and the dest.
310 std::string
desc_string(desc_for_err
);
311 *err
= Err(node_for_err
, "Assignment filter collision.",
312 "The " + desc_string
+ " contains a sources_assignment_filter "
313 "which\nwould clobber the one in your current scope.");
317 dest
->sources_assignment_filter_
.reset(
318 new PatternList(*sources_assignment_filter_
));
322 for (const auto& pair
: templates_
) {
323 if (options
.skip_private_vars
&& IsPrivateVar(pair
.first
))
324 continue; // Skip this private template.
326 if (!options
.clobber_existing
) {
327 const Template
* existing_template
= dest
->GetTemplate(pair
.first
);
328 // Since templates are refcounted, we can check if it's the same one by
329 // comparing pointers.
330 if (existing_template
&& pair
.second
.get() != existing_template
) {
331 // Rule present in both the source and the dest, and they're not the
333 std::string
desc_string(desc_for_err
);
334 *err
= Err(node_for_err
, "Template collision.",
335 "This " + desc_string
+ " contains a template \"" +
337 err
->AppendSubErr(Err(pair
.second
->GetDefinitionRange(),
339 "Which would clobber the one in your current scope"));
340 err
->AppendSubErr(Err(existing_template
->GetDefinitionRange(),
342 "Executing " + desc_string
+ " should not conflict with anything "
343 "in the current\nscope."));
348 // Be careful to delete any pointer we're about to clobber.
349 dest
->templates_
[pair
.first
] = pair
.second
;
355 scoped_ptr
<Scope
> Scope::MakeClosure() const {
356 scoped_ptr
<Scope
> result
;
357 if (const_containing_
) {
358 // We reached the top of the mutable scope stack. The result scope just
359 // references the const scope (which will never change).
360 result
.reset(new Scope(const_containing_
));
361 } else if (mutable_containing_
) {
362 // There are more nested mutable scopes. Recursively go up the stack to
364 result
= mutable_containing_
->MakeClosure();
366 // This is a standalone scope, just copy it.
367 result
.reset(new Scope(settings_
));
370 // Want to clobber since we've flattened some nested scopes, and our parent
371 // scope may have a duplicate value set.
372 MergeOptions options
;
373 options
.clobber_existing
= true;
375 // Add in our variables and we're done.
377 NonRecursiveMergeTo(result
.get(), options
, nullptr, "<SHOULDN'T HAPPEN>",
379 DCHECK(!err
.has_error());
380 return result
.Pass();
383 Scope
* Scope::MakeTargetDefaults(const std::string
& target_type
) {
384 if (GetTargetDefaults(target_type
))
387 Scope
** dest
= &target_defaults_
[target_type
];
389 NOTREACHED(); // Already set.
392 *dest
= new Scope(settings_
);
396 const Scope
* Scope::GetTargetDefaults(const std::string
& target_type
) const {
397 NamedScopeMap::const_iterator found
= target_defaults_
.find(target_type
);
398 if (found
!= target_defaults_
.end())
399 return found
->second
;
401 return containing()->GetTargetDefaults(target_type
);
405 const PatternList
* Scope::GetSourcesAssignmentFilter() const {
406 if (sources_assignment_filter_
)
407 return sources_assignment_filter_
.get();
409 return containing()->GetSourcesAssignmentFilter();
413 void Scope::SetProcessingBuildConfig() {
414 DCHECK((mode_flags_
& kProcessingBuildConfigFlag
) == 0);
415 mode_flags_
|= kProcessingBuildConfigFlag
;
418 void Scope::ClearProcessingBuildConfig() {
419 DCHECK(mode_flags_
& kProcessingBuildConfigFlag
);
420 mode_flags_
&= ~(kProcessingBuildConfigFlag
);
423 bool Scope::IsProcessingBuildConfig() const {
424 if (mode_flags_
& kProcessingBuildConfigFlag
)
427 return containing()->IsProcessingBuildConfig();
431 void Scope::SetProcessingImport() {
432 DCHECK((mode_flags_
& kProcessingImportFlag
) == 0);
433 mode_flags_
|= kProcessingImportFlag
;
436 void Scope::ClearProcessingImport() {
437 DCHECK(mode_flags_
& kProcessingImportFlag
);
438 mode_flags_
&= ~(kProcessingImportFlag
);
441 bool Scope::IsProcessingImport() const {
442 if (mode_flags_
& kProcessingImportFlag
)
445 return containing()->IsProcessingImport();
449 const SourceDir
& Scope::GetSourceDir() const {
450 if (!source_dir_
.is_null())
453 return containing()->GetSourceDir();
457 Scope::ItemVector
* Scope::GetItemCollector() {
459 return item_collector_
;
460 if (mutable_containing())
461 return mutable_containing()->GetItemCollector();
465 void Scope::SetProperty(const void* key
, void* value
) {
467 DCHECK(properties_
.find(key
) != properties_
.end());
468 properties_
.erase(key
);
470 properties_
[key
] = value
;
474 void* Scope::GetProperty(const void* key
, const Scope
** found_on_scope
) const {
475 PropertyMap::const_iterator found
= properties_
.find(key
);
476 if (found
!= properties_
.end()) {
478 *found_on_scope
= this;
479 return found
->second
;
482 return containing()->GetProperty(key
, found_on_scope
);
486 void Scope::AddProvider(ProgrammaticProvider
* p
) {
487 programmatic_providers_
.insert(p
);
490 void Scope::RemoveProvider(ProgrammaticProvider
* p
) {
491 DCHECK(programmatic_providers_
.find(p
) != programmatic_providers_
.end());
492 programmatic_providers_
.erase(p
);