OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "tools/gn/scope.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/stl_util.h" | |
9 #include "tools/gn/parse_tree.h" | |
10 | |
11 namespace { | |
12 | |
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 kProcessingDefaultBuildConfigFlag = 2; | |
17 const unsigned kProcessingImportFlag = 4; | |
18 | |
19 } // namespace | |
20 | |
21 Scope::Scope(const Settings* settings) | |
22 : const_containing_(NULL), | |
23 mutable_containing_(NULL), | |
24 settings_(settings), | |
25 mode_flags_(0) { | |
26 } | |
27 | |
28 Scope::Scope(Scope* parent) | |
29 : const_containing_(NULL), | |
30 mutable_containing_(parent), | |
31 settings_(parent->settings()), | |
32 mode_flags_(0) { | |
33 } | |
34 | |
35 Scope::Scope(const Scope* parent) | |
36 : const_containing_(parent), | |
37 mutable_containing_(NULL), | |
38 settings_(parent->settings()), | |
39 mode_flags_(0) { | |
40 } | |
41 | |
42 Scope::~Scope() { | |
43 STLDeleteContainerPairSecondPointers(target_defaults_.begin(), | |
44 target_defaults_.end()); | |
45 } | |
46 | |
47 const Value* Scope::GetValue(const base::StringPiece& ident, | |
48 bool counts_as_used) { | |
49 // First check for programatically-provided values. | |
50 for (ProviderSet::const_iterator i = programmatic_providers_.begin(); | |
51 i != programmatic_providers_.end(); ++i) { | |
52 const Value* v = (*i)->GetProgrammaticValue(ident); | |
53 if (v) | |
54 return v; | |
55 } | |
56 | |
57 RecordMap::iterator found = values_.find(ident); | |
58 if (found != values_.end()) { | |
59 if (counts_as_used) | |
60 found->second.used = true; | |
61 return &found->second.value; | |
62 } | |
63 | |
64 // Search in the parent scope. | |
65 if (const_containing_) | |
66 return const_containing_->GetValue(ident); | |
67 if (mutable_containing_) | |
68 return mutable_containing_->GetValue(ident, counts_as_used); | |
69 return NULL; | |
70 } | |
71 | |
72 Value* Scope::GetValueForcedToCurrentScope(const base::StringPiece& ident, | |
73 const ParseNode* set_node) { | |
74 RecordMap::iterator found = values_.find(ident); | |
75 if (found != values_.end()) | |
76 return &found->second.value; // Already have in the current scope. | |
77 | |
78 // Search in the parent scope. | |
79 if (containing()) { | |
80 const Value* in_containing = containing()->GetValue(ident); | |
81 if (in_containing) { | |
82 // Promote to current scope. | |
83 return SetValue(ident, *in_containing, set_node); | |
84 } | |
85 } | |
86 return NULL; | |
87 } | |
88 | |
89 const Value* Scope::GetValue(const base::StringPiece& ident) const { | |
90 RecordMap::const_iterator found = values_.find(ident); | |
91 if (found != values_.end()) | |
92 return &found->second.value; | |
93 if (containing()) | |
94 return containing()->GetValue(ident); | |
95 return NULL; | |
96 } | |
97 | |
98 Value* Scope::SetValue(const base::StringPiece& ident, | |
99 const Value& v, | |
100 const ParseNode* set_node) { | |
101 Record& r = values_[ident]; // Clears any existing value. | |
102 r.value = v; | |
103 r.value.set_origin(set_node); | |
104 return &r.value; | |
105 } | |
106 | |
107 bool Scope::AddTemplate(const std::string& name, const FunctionCallNode* decl) { | |
108 if (GetTemplate(name)) | |
109 return false; | |
110 templates_[name] = decl; | |
111 return true; | |
112 } | |
113 | |
114 const FunctionCallNode* Scope::GetTemplate(const std::string& name) const { | |
115 TemplateMap::const_iterator found = templates_.find(name); | |
116 if (found != templates_.end()) | |
117 return found->second; | |
118 if (containing()) | |
119 return containing()->GetTemplate(name); | |
120 return NULL; | |
121 } | |
122 | |
123 void Scope::MarkUsed(const base::StringPiece& ident) { | |
124 RecordMap::iterator found = values_.find(ident); | |
125 if (found == values_.end()) { | |
126 NOTREACHED(); | |
127 return; | |
128 } | |
129 found->second.used = true; | |
130 } | |
131 | |
132 void Scope::MarkUnused(const base::StringPiece& ident) { | |
133 RecordMap::iterator found = values_.find(ident); | |
134 if (found == values_.end()) { | |
135 NOTREACHED(); | |
136 return; | |
137 } | |
138 found->second.used = false; | |
139 } | |
140 | |
141 bool Scope::IsSetButUnused(const base::StringPiece& ident) const { | |
142 RecordMap::const_iterator found = values_.find(ident); | |
143 if (found != values_.end()) { | |
144 if (!found->second.used) { | |
145 return true; | |
146 } | |
147 } | |
148 return false; | |
149 } | |
150 | |
151 bool Scope::CheckForUnusedVars(Err* err) const { | |
152 for (RecordMap::const_iterator i = values_.begin(); | |
153 i != values_.end(); ++i) { | |
154 if (!i->second.used) { | |
155 std::string help = "You set the variable \"" + i->first.as_string() + | |
156 "\" here and it was unused before it went\nout of scope."; | |
157 | |
158 const BinaryOpNode* binary = i->second.value.origin()->AsBinaryOp(); | |
159 if (binary) { | |
160 // Make a nicer error message for normal var sets. | |
161 *err = Err(binary->left()->GetRange(), "Assignment had no effect.", | |
162 help); | |
163 } else { | |
164 // This will happen for internally-generated variables. | |
165 *err = Err(i->second.value.origin(), "Assignment had no effect.", help); | |
166 } | |
167 return false; | |
168 } | |
169 } | |
170 return true; | |
171 } | |
172 | |
173 void Scope::GetCurrentScopeValues(KeyValueVector* output) const { | |
174 output->reserve(values_.size()); | |
175 for (RecordMap::const_iterator i = values_.begin(); i != values_.end(); ++i) { | |
176 output->push_back(std::make_pair(i->first, i->second.value)); | |
177 } | |
178 } | |
179 | |
180 bool Scope::NonRecursiveMergeTo(Scope* dest, | |
181 const ParseNode* node_for_err, | |
182 const char* desc_for_err, | |
183 Err* err) const { | |
184 // Values. | |
185 for (RecordMap::const_iterator i = values_.begin(); i != values_.end(); ++i) { | |
186 const Value* existing_value = dest->GetValue(i->first); | |
187 if (existing_value) { | |
188 // Value present in both the source and the dest. | |
189 std::string desc_string(desc_for_err); | |
190 *err = Err(node_for_err, "Value collision.", | |
191 "This " + desc_string + " contains \"" + i->first.as_string() + "\""); | |
192 err->AppendSubErr(Err(i->second.value, "defined here.", | |
193 "Which would clobber the one in your current scope")); | |
194 err->AppendSubErr(Err(*existing_value, "defined here.", | |
195 "Executing " + desc_string + " should not conflict with anything " | |
196 "in the current\nscope.")); | |
197 return false; | |
198 } | |
199 dest->values_[i->first] = i->second; | |
200 } | |
201 | |
202 // Target defaults are owning pointers. | |
203 for (NamedScopeMap::const_iterator i = target_defaults_.begin(); | |
204 i != target_defaults_.end(); ++i) { | |
205 if (dest->GetTargetDefaults(i->first)) { | |
206 // TODO(brettw) it would be nice to know the origin of a | |
207 // set_target_defaults so we can give locations for the colliding target | |
208 // defaults. | |
209 std::string desc_string(desc_for_err); | |
210 *err = Err(node_for_err, "Target defaults collision.", | |
211 "This " + desc_string + " contains target defaults for\n" | |
212 "\"" + i->first + "\" which would clobber one for the\n" | |
213 "same target type in your current scope. It's unfortunate that I'm " | |
214 "too stupid\nto tell you the location of where the target defaults " | |
215 "were set. Usually\nthis happens in the BUILDCONFIG.gn file."); | |
216 return false; | |
217 } | |
218 | |
219 Scope* s = new Scope(settings_); | |
220 i->second->NonRecursiveMergeTo(s, node_for_err, "<SHOULDN'T HAPPEN>", err); | |
221 dest->target_defaults_[i->first] = s; | |
222 } | |
223 | |
224 // Sources assignment filter. | |
225 if (sources_assignment_filter_) { | |
226 if (dest->GetSourcesAssignmentFilter()) { | |
227 // Sources assignment filter present in both the source and the dest. | |
228 std::string desc_string(desc_for_err); | |
229 *err = Err(node_for_err, "Assignment filter collision.", | |
230 "The " + desc_string + " contains a sources_assignment_filter which\n" | |
231 "would clobber the one in your current scope."); | |
232 return false; | |
233 } | |
234 dest->sources_assignment_filter_.reset( | |
235 new PatternList(*sources_assignment_filter_)); | |
236 } | |
237 | |
238 // Templates. | |
239 for (TemplateMap::const_iterator i = templates_.begin(); | |
240 i != templates_.end(); ++i) { | |
241 const FunctionCallNode* existing_template = dest->GetTemplate(i->first); | |
242 if (existing_template) { | |
243 // Rule present in both the source and the dest. | |
244 std::string desc_string(desc_for_err); | |
245 *err = Err(node_for_err, "Template collision.", | |
246 "This " + desc_string + " contains a template \"" + i->first + "\""); | |
247 err->AppendSubErr(Err(i->second->function(), "defined here.", | |
248 "Which would clobber the one in your current scope")); | |
249 err->AppendSubErr(Err(existing_template->function(), "defined here.", | |
250 "Executing " + desc_string + " should not conflict with anything " | |
251 "in the current\nscope.")); | |
252 return false; | |
253 } | |
254 dest->templates_.insert(*i); | |
255 } | |
256 | |
257 return true; | |
258 } | |
259 | |
260 Scope* Scope::MakeTargetDefaults(const std::string& target_type) { | |
261 if (GetTargetDefaults(target_type)) | |
262 return NULL; | |
263 | |
264 Scope** dest = &target_defaults_[target_type]; | |
265 if (*dest) { | |
266 NOTREACHED(); // Already set. | |
267 return *dest; | |
268 } | |
269 *dest = new Scope(settings_); | |
270 return *dest; | |
271 } | |
272 | |
273 const Scope* Scope::GetTargetDefaults(const std::string& target_type) const { | |
274 NamedScopeMap::const_iterator found = target_defaults_.find(target_type); | |
275 if (found != target_defaults_.end()) | |
276 return found->second; | |
277 if (containing()) | |
278 return containing()->GetTargetDefaults(target_type); | |
279 return NULL; | |
280 } | |
281 | |
282 const PatternList* Scope::GetSourcesAssignmentFilter() const { | |
283 if (sources_assignment_filter_) | |
284 return sources_assignment_filter_.get(); | |
285 if (containing()) | |
286 return containing()->GetSourcesAssignmentFilter(); | |
287 return NULL; | |
288 } | |
289 | |
290 void Scope::SetProcessingBuildConfig() { | |
291 DCHECK((mode_flags_ & kProcessingBuildConfigFlag) == 0); | |
292 mode_flags_ |= kProcessingBuildConfigFlag; | |
293 } | |
294 | |
295 void Scope::ClearProcessingBuildConfig() { | |
296 DCHECK(mode_flags_ & kProcessingBuildConfigFlag); | |
297 mode_flags_ &= ~(kProcessingBuildConfigFlag); | |
298 } | |
299 | |
300 bool Scope::IsProcessingBuildConfig() const { | |
301 if (mode_flags_ & kProcessingBuildConfigFlag) | |
302 return true; | |
303 if (containing()) | |
304 return containing()->IsProcessingBuildConfig(); | |
305 return false; | |
306 } | |
307 | |
308 void Scope::SetProcessingDefaultBuildConfig() { | |
309 DCHECK((mode_flags_ & kProcessingDefaultBuildConfigFlag) == 0); | |
310 mode_flags_ |= kProcessingDefaultBuildConfigFlag; | |
311 } | |
312 | |
313 void Scope::ClearProcessingDefaultBuildConfig() { | |
314 DCHECK(mode_flags_ & kProcessingDefaultBuildConfigFlag); | |
315 mode_flags_ &= ~(kProcessingDefaultBuildConfigFlag); | |
316 } | |
317 | |
318 bool Scope::IsProcessingDefaultBuildConfig() const { | |
319 if (mode_flags_ & kProcessingDefaultBuildConfigFlag) | |
320 return true; | |
321 if (containing()) | |
322 return containing()->IsProcessingDefaultBuildConfig(); | |
323 return false; | |
324 } | |
325 | |
326 void Scope::SetProcessingImport() { | |
327 DCHECK((mode_flags_ & kProcessingImportFlag) == 0); | |
328 mode_flags_ |= kProcessingImportFlag; | |
329 } | |
330 | |
331 void Scope::ClearProcessingImport() { | |
332 DCHECK(mode_flags_ & kProcessingImportFlag); | |
333 mode_flags_ &= ~(kProcessingImportFlag); | |
334 } | |
335 | |
336 bool Scope::IsProcessingImport() const { | |
337 if (mode_flags_ & kProcessingImportFlag) | |
338 return true; | |
339 if (containing()) | |
340 return containing()->IsProcessingImport(); | |
341 return false; | |
342 } | |
343 | |
344 void Scope::SetProperty(const void* key, void* value) { | |
345 if (!value) { | |
346 DCHECK(properties_.find(key) != properties_.end()); | |
347 properties_.erase(key); | |
348 } else { | |
349 properties_[key] = value; | |
350 } | |
351 } | |
352 | |
353 void* Scope::GetProperty(const void* key, const Scope** found_on_scope) const { | |
354 PropertyMap::const_iterator found = properties_.find(key); | |
355 if (found != properties_.end()) { | |
356 if (found_on_scope) | |
357 *found_on_scope = this; | |
358 return found->second; | |
359 } | |
360 if (containing()) | |
361 return containing()->GetProperty(key, found_on_scope); | |
362 return NULL; | |
363 } | |
364 | |
365 void Scope::AddProvider(ProgrammaticProvider* p) { | |
366 programmatic_providers_.insert(p); | |
367 } | |
368 | |
369 void Scope::RemoveProvider(ProgrammaticProvider* p) { | |
370 DCHECK(programmatic_providers_.find(p) != programmatic_providers_.end()); | |
371 programmatic_providers_.erase(p); | |
372 } | |
OLD | NEW |