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 |