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"
13 // FLags set in the mode_flags_ of a scope. If a bit is set, it applies
14 // recursively to all dependent scopes.
15 const unsigned kProcessingBuildConfigFlag
= 1;
16 const unsigned kProcessingImportFlag
= 2;
20 Scope::Scope(const Settings
* settings
)
21 : const_containing_(NULL
),
22 mutable_containing_(NULL
),
27 Scope::Scope(Scope
* parent
)
28 : const_containing_(NULL
),
29 mutable_containing_(parent
),
30 settings_(parent
->settings()),
34 Scope::Scope(const Scope
* parent
)
35 : const_containing_(parent
),
36 mutable_containing_(NULL
),
37 settings_(parent
->settings()),
42 STLDeleteContainerPairSecondPointers(target_defaults_
.begin(),
43 target_defaults_
.end());
46 const Value
* Scope::GetValue(const base::StringPiece
& ident
,
47 bool counts_as_used
) {
48 // First check for programatically-provided values.
49 for (ProviderSet::const_iterator i
= programmatic_providers_
.begin();
50 i
!= programmatic_providers_
.end(); ++i
) {
51 const Value
* v
= (*i
)->GetProgrammaticValue(ident
);
56 RecordMap::iterator found
= values_
.find(ident
);
57 if (found
!= values_
.end()) {
59 found
->second
.used
= true;
60 return &found
->second
.value
;
63 // Search in the parent scope.
64 if (const_containing_
)
65 return const_containing_
->GetValue(ident
);
66 if (mutable_containing_
)
67 return mutable_containing_
->GetValue(ident
, counts_as_used
);
71 Value
* Scope::GetValueForcedToCurrentScope(const base::StringPiece
& ident
,
72 const ParseNode
* set_node
) {
73 RecordMap::iterator found
= values_
.find(ident
);
74 if (found
!= values_
.end())
75 return &found
->second
.value
; // Already have in the current scope.
77 // Search in the parent scope.
79 const Value
* in_containing
= containing()->GetValue(ident
);
81 // Promote to current scope.
82 return SetValue(ident
, *in_containing
, set_node
);
88 const Value
* Scope::GetValue(const base::StringPiece
& ident
) const {
89 RecordMap::const_iterator found
= values_
.find(ident
);
90 if (found
!= values_
.end())
91 return &found
->second
.value
;
93 return containing()->GetValue(ident
);
97 Value
* Scope::SetValue(const base::StringPiece
& ident
,
99 const ParseNode
* set_node
) {
100 Record
& r
= values_
[ident
]; // Clears any existing value.
102 r
.value
.set_origin(set_node
);
106 bool Scope::AddTemplate(const std::string
& name
, const FunctionCallNode
* decl
) {
107 if (GetTemplate(name
))
109 templates_
[name
] = decl
;
113 const FunctionCallNode
* Scope::GetTemplate(const std::string
& name
) const {
114 TemplateMap::const_iterator found
= templates_
.find(name
);
115 if (found
!= templates_
.end())
116 return found
->second
;
118 return containing()->GetTemplate(name
);
122 void Scope::MarkUsed(const base::StringPiece
& ident
) {
123 RecordMap::iterator found
= values_
.find(ident
);
124 if (found
== values_
.end()) {
128 found
->second
.used
= true;
131 void Scope::MarkUnused(const base::StringPiece
& ident
) {
132 RecordMap::iterator found
= values_
.find(ident
);
133 if (found
== values_
.end()) {
137 found
->second
.used
= false;
140 bool Scope::IsSetButUnused(const base::StringPiece
& ident
) const {
141 RecordMap::const_iterator found
= values_
.find(ident
);
142 if (found
!= values_
.end()) {
143 if (!found
->second
.used
) {
150 bool Scope::CheckForUnusedVars(Err
* err
) const {
151 for (RecordMap::const_iterator i
= values_
.begin();
152 i
!= values_
.end(); ++i
) {
153 if (!i
->second
.used
) {
154 std::string help
= "You set the variable \"" + i
->first
.as_string() +
155 "\" here and it was unused before it went\nout of scope.";
157 const BinaryOpNode
* binary
= i
->second
.value
.origin()->AsBinaryOp();
158 if (binary
&& binary
->op().type() == Token::EQUAL
) {
159 // Make a nicer error message for normal var sets.
160 *err
= Err(binary
->left()->GetRange(), "Assignment had no effect.",
163 // This will happen for internally-generated variables.
164 *err
= Err(i
->second
.value
.origin(), "Assignment had no effect.", help
);
172 void Scope::GetCurrentScopeValues(KeyValueMap
* output
) const {
173 for (RecordMap::const_iterator i
= values_
.begin(); i
!= values_
.end(); ++i
)
174 (*output
)[i
->first
] = i
->second
.value
;
177 bool Scope::NonRecursiveMergeTo(Scope
* dest
,
178 const ParseNode
* node_for_err
,
179 const char* desc_for_err
,
182 for (RecordMap::const_iterator i
= values_
.begin(); i
!= values_
.end(); ++i
) {
183 const Value
& new_value
= i
->second
.value
;
184 const Value
* existing_value
= dest
->GetValue(i
->first
);
185 if (existing_value
&& new_value
!= *existing_value
) {
186 // Value present in both the source and the dest.
187 std::string
desc_string(desc_for_err
);
188 *err
= Err(node_for_err
, "Value collision.",
189 "This " + desc_string
+ " contains \"" + i
->first
.as_string() + "\"");
190 err
->AppendSubErr(Err(i
->second
.value
, "defined here.",
191 "Which would clobber the one in your current scope"));
192 err
->AppendSubErr(Err(*existing_value
, "defined here.",
193 "Executing " + desc_string
+ " should not conflict with anything "
194 "in the current\nscope unless the values are identical."));
197 dest
->values_
[i
->first
] = i
->second
;
200 // Target defaults are owning pointers.
201 for (NamedScopeMap::const_iterator i
= target_defaults_
.begin();
202 i
!= target_defaults_
.end(); ++i
) {
203 if (dest
->GetTargetDefaults(i
->first
)) {
204 // TODO(brettw) it would be nice to know the origin of a
205 // set_target_defaults so we can give locations for the colliding target
207 std::string
desc_string(desc_for_err
);
208 *err
= Err(node_for_err
, "Target defaults collision.",
209 "This " + desc_string
+ " contains target defaults for\n"
210 "\"" + i
->first
+ "\" which would clobber one for the\n"
211 "same target type in your current scope. It's unfortunate that I'm "
212 "too stupid\nto tell you the location of where the target defaults "
213 "were set. Usually\nthis happens in the BUILDCONFIG.gn file.");
217 Scope
* s
= new Scope(settings_
);
218 i
->second
->NonRecursiveMergeTo(s
, node_for_err
, "<SHOULDN'T HAPPEN>", err
);
219 dest
->target_defaults_
[i
->first
] = s
;
222 // Sources assignment filter.
223 if (sources_assignment_filter_
) {
224 if (dest
->GetSourcesAssignmentFilter()) {
225 // Sources assignment filter present in both the source and the dest.
226 std::string
desc_string(desc_for_err
);
227 *err
= Err(node_for_err
, "Assignment filter collision.",
228 "The " + desc_string
+ " contains a sources_assignment_filter which\n"
229 "would clobber the one in your current scope.");
232 dest
->sources_assignment_filter_
.reset(
233 new PatternList(*sources_assignment_filter_
));
237 for (TemplateMap::const_iterator i
= templates_
.begin();
238 i
!= templates_
.end(); ++i
) {
239 const FunctionCallNode
* existing_template
= dest
->GetTemplate(i
->first
);
240 if (existing_template
) {
241 // Rule present in both the source and the dest.
242 std::string
desc_string(desc_for_err
);
243 *err
= Err(node_for_err
, "Template collision.",
244 "This " + desc_string
+ " contains a template \"" + i
->first
+ "\"");
245 err
->AppendSubErr(Err(i
->second
->function(), "defined here.",
246 "Which would clobber the one in your current scope"));
247 err
->AppendSubErr(Err(existing_template
->function(), "defined here.",
248 "Executing " + desc_string
+ " should not conflict with anything "
249 "in the current\nscope."));
252 dest
->templates_
.insert(*i
);
258 Scope
* Scope::MakeTargetDefaults(const std::string
& target_type
) {
259 if (GetTargetDefaults(target_type
))
262 Scope
** dest
= &target_defaults_
[target_type
];
264 NOTREACHED(); // Already set.
267 *dest
= new Scope(settings_
);
271 const Scope
* Scope::GetTargetDefaults(const std::string
& target_type
) const {
272 NamedScopeMap::const_iterator found
= target_defaults_
.find(target_type
);
273 if (found
!= target_defaults_
.end())
274 return found
->second
;
276 return containing()->GetTargetDefaults(target_type
);
280 const PatternList
* Scope::GetSourcesAssignmentFilter() const {
281 if (sources_assignment_filter_
)
282 return sources_assignment_filter_
.get();
284 return containing()->GetSourcesAssignmentFilter();
288 void Scope::SetProcessingBuildConfig() {
289 DCHECK((mode_flags_
& kProcessingBuildConfigFlag
) == 0);
290 mode_flags_
|= kProcessingBuildConfigFlag
;
293 void Scope::ClearProcessingBuildConfig() {
294 DCHECK(mode_flags_
& kProcessingBuildConfigFlag
);
295 mode_flags_
&= ~(kProcessingBuildConfigFlag
);
298 bool Scope::IsProcessingBuildConfig() const {
299 if (mode_flags_
& kProcessingBuildConfigFlag
)
302 return containing()->IsProcessingBuildConfig();
306 void Scope::SetProcessingImport() {
307 DCHECK((mode_flags_
& kProcessingImportFlag
) == 0);
308 mode_flags_
|= kProcessingImportFlag
;
311 void Scope::ClearProcessingImport() {
312 DCHECK(mode_flags_
& kProcessingImportFlag
);
313 mode_flags_
&= ~(kProcessingImportFlag
);
316 bool Scope::IsProcessingImport() const {
317 if (mode_flags_
& kProcessingImportFlag
)
320 return containing()->IsProcessingImport();
324 const SourceDir
& Scope::GetSourceDir() const {
325 if (!source_dir_
.is_null())
328 return containing()->GetSourceDir();
332 void Scope::SetProperty(const void* key
, void* value
) {
334 DCHECK(properties_
.find(key
) != properties_
.end());
335 properties_
.erase(key
);
337 properties_
[key
] = value
;
341 void* Scope::GetProperty(const void* key
, const Scope
** found_on_scope
) const {
342 PropertyMap::const_iterator found
= properties_
.find(key
);
343 if (found
!= properties_
.end()) {
345 *found_on_scope
= this;
346 return found
->second
;
349 return containing()->GetProperty(key
, found_on_scope
);
353 void Scope::AddProvider(ProgrammaticProvider
* p
) {
354 programmatic_providers_
.insert(p
);
357 void Scope::RemoveProvider(ProgrammaticProvider
* p
) {
358 DCHECK(programmatic_providers_
.find(p
) != programmatic_providers_
.end());
359 programmatic_providers_
.erase(p
);