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 #include "tools/gn/template.h" 11 12 namespace { 13 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; 18 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] == '_'; 24 } 25 26 } // namespace 27 28 Scope::Scope(const Settings* settings) 29 : const_containing_(NULL), 30 mutable_containing_(NULL), 31 settings_(settings), 32 mode_flags_(0), 33 item_collector_(NULL) { 34 } 35 36 Scope::Scope(Scope* parent) 37 : const_containing_(NULL), 38 mutable_containing_(parent), 39 settings_(parent->settings()), 40 mode_flags_(0), 41 item_collector_(NULL) { 42 } 43 44 Scope::Scope(const Scope* parent) 45 : const_containing_(parent), 46 mutable_containing_(NULL), 47 settings_(parent->settings()), 48 mode_flags_(0), 49 item_collector_(NULL) { 50 } 51 52 Scope::~Scope() { 53 STLDeleteContainerPairSecondPointers(target_defaults_.begin(), 54 target_defaults_.end()); 55 } 56 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); 63 if (v) 64 return v; 65 } 66 67 RecordMap::iterator found = values_.find(ident); 68 if (found != values_.end()) { 69 if (counts_as_used) 70 found->second.used = true; 71 return &found->second.value; 72 } 73 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); 79 return NULL; 80 } 81 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()) { 87 if (counts_as_used) 88 found->second.used = true; 89 return &found->second.value; 90 } 91 92 // Search in the parent mutable scope, but not const one. 93 if (mutable_containing_) 94 return mutable_containing_->GetMutableValue(ident, counts_as_used); 95 return NULL; 96 } 97 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. 103 104 // Search in the parent scope. 105 if (containing()) { 106 const Value* in_containing = containing()->GetValue(ident); 107 if (in_containing) { 108 // Promote to current scope. 109 return SetValue(ident, *in_containing, set_node); 110 } 111 } 112 return NULL; 113 } 114 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; 119 if (containing()) 120 return containing()->GetValue(ident); 121 return NULL; 122 } 123 124 Value* Scope::SetValue(const base::StringPiece& ident, 125 const Value& v, 126 const ParseNode* set_node) { 127 Record& r = values_[ident]; // Clears any existing value. 128 r.value = v; 129 r.value.set_origin(set_node); 130 return &r.value; 131 } 132 133 void Scope::RemoveIdentifier(const base::StringPiece& ident) { 134 RecordMap::iterator found = values_.find(ident); 135 if (found != values_.end()) 136 values_.erase(found); 137 } 138 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); 148 } 149 150 for (size_t i = 0; i < to_remove.size(); i++) 151 values_.erase(to_remove[i]); 152 } 153 154 bool Scope::AddTemplate(const std::string& name, const Template* templ) { 155 if (GetTemplate(name)) 156 return false; 157 templates_[name] = templ; 158 return true; 159 } 160 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(); 165 if (containing()) 166 return containing()->GetTemplate(name); 167 return NULL; 168 } 169 170 void Scope::MarkUsed(const base::StringPiece& ident) { 171 RecordMap::iterator found = values_.find(ident); 172 if (found == values_.end()) { 173 NOTREACHED(); 174 return; 175 } 176 found->second.used = true; 177 } 178 179 void Scope::MarkUnused(const base::StringPiece& ident) { 180 RecordMap::iterator found = values_.find(ident); 181 if (found == values_.end()) { 182 NOTREACHED(); 183 return; 184 } 185 found->second.used = false; 186 } 187 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) { 192 return true; 193 } 194 } 195 return false; 196 } 197 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."; 204 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.", 209 help); 210 } else { 211 // This will happen for internally-generated variables. 212 *err = Err(i->second.value.origin(), "Assignment had no effect.", help); 213 } 214 return false; 215 } 216 } 217 return true; 218 } 219 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; 223 } 224 225 bool Scope::NonRecursiveMergeTo(Scope* dest, 226 const MergeOptions& options, 227 const ParseNode* node_for_err, 228 const char* desc_for_err, 229 Err* err) const { 230 // Values. 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. 234 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() + 243 "\""); 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.")); 249 return false; 250 } 251 } 252 dest->values_[i->first] = i->second; 253 254 if (options.mark_used) 255 dest->MarkUsed(i->first); 256 } 257 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 265 // defaults. 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."); 273 return false; 274 } 275 } 276 277 // Be careful to delete any pointer we're about to clobber. 278 Scope** dest_scope = &dest->target_defaults_[i->first]; 279 if (*dest_scope) 280 delete *dest_scope; 281 *dest_scope = new Scope(settings_); 282 i->second->NonRecursiveMergeTo(*dest_scope, options, node_for_err, 283 "<SHOULDN'T HAPPEN>", err); 284 } 285 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."); 295 return false; 296 } 297 } 298 dest->sources_assignment_filter_.reset( 299 new PatternList(*sources_assignment_filter_)); 300 } 301 302 // Templates. 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. 307 308 if (!options.clobber_existing) { 309 const Template* existing_template = dest->GetTemplate(i->first); 310 // Since templates are refcounted, we can check if it's the same one by 311 // comparing pointers. 312 if (existing_template && i->second.get() != existing_template) { 313 // Rule present in both the source and the dest, and they're not the 314 // same one. 315 std::string desc_string(desc_for_err); 316 *err = Err(node_for_err, "Template collision.", 317 "This " + desc_string + " contains a template \"" + 318 i->first + "\""); 319 err->AppendSubErr(Err(i->second->GetDefinitionRange(), "defined here.", 320 "Which would clobber the one in your current scope")); 321 err->AppendSubErr(Err(existing_template->GetDefinitionRange(), 322 "defined here.", 323 "Executing " + desc_string + " should not conflict with anything " 324 "in the current\nscope.")); 325 return false; 326 } 327 } 328 329 // Be careful to delete any pointer we're about to clobber. 330 dest->templates_[i->first] = i->second; 331 } 332 333 return true; 334 } 335 336 scoped_ptr<Scope> Scope::MakeClosure() const { 337 scoped_ptr<Scope> result; 338 if (const_containing_) { 339 // We reached the top of the mutable scope stack. The result scope just 340 // references the const scope (which will never change). 341 result.reset(new Scope(const_containing_)); 342 } else if (mutable_containing_) { 343 // There are more nested mutable scopes. Recursively go up the stack to 344 // get the closure. 345 result = mutable_containing_->MakeClosure(); 346 } else { 347 // This is a standalone scope, just copy it. 348 result.reset(new Scope(settings_)); 349 } 350 351 // Want to clobber since we've flattened some nested scopes, and our parent 352 // scope may have a duplicate value set. 353 MergeOptions options; 354 options.clobber_existing = true; 355 356 // Add in our variables and we're done. 357 Err err; 358 NonRecursiveMergeTo(result.get(), options, NULL, "<SHOULDN'T HAPPEN>", &err); 359 DCHECK(!err.has_error()); 360 return result.Pass(); 361 } 362 363 Scope* Scope::MakeTargetDefaults(const std::string& target_type) { 364 if (GetTargetDefaults(target_type)) 365 return NULL; 366 367 Scope** dest = &target_defaults_[target_type]; 368 if (*dest) { 369 NOTREACHED(); // Already set. 370 return *dest; 371 } 372 *dest = new Scope(settings_); 373 return *dest; 374 } 375 376 const Scope* Scope::GetTargetDefaults(const std::string& target_type) const { 377 NamedScopeMap::const_iterator found = target_defaults_.find(target_type); 378 if (found != target_defaults_.end()) 379 return found->second; 380 if (containing()) 381 return containing()->GetTargetDefaults(target_type); 382 return NULL; 383 } 384 385 const PatternList* Scope::GetSourcesAssignmentFilter() const { 386 if (sources_assignment_filter_) 387 return sources_assignment_filter_.get(); 388 if (containing()) 389 return containing()->GetSourcesAssignmentFilter(); 390 return NULL; 391 } 392 393 void Scope::SetProcessingBuildConfig() { 394 DCHECK((mode_flags_ & kProcessingBuildConfigFlag) == 0); 395 mode_flags_ |= kProcessingBuildConfigFlag; 396 } 397 398 void Scope::ClearProcessingBuildConfig() { 399 DCHECK(mode_flags_ & kProcessingBuildConfigFlag); 400 mode_flags_ &= ~(kProcessingBuildConfigFlag); 401 } 402 403 bool Scope::IsProcessingBuildConfig() const { 404 if (mode_flags_ & kProcessingBuildConfigFlag) 405 return true; 406 if (containing()) 407 return containing()->IsProcessingBuildConfig(); 408 return false; 409 } 410 411 void Scope::SetProcessingImport() { 412 DCHECK((mode_flags_ & kProcessingImportFlag) == 0); 413 mode_flags_ |= kProcessingImportFlag; 414 } 415 416 void Scope::ClearProcessingImport() { 417 DCHECK(mode_flags_ & kProcessingImportFlag); 418 mode_flags_ &= ~(kProcessingImportFlag); 419 } 420 421 bool Scope::IsProcessingImport() const { 422 if (mode_flags_ & kProcessingImportFlag) 423 return true; 424 if (containing()) 425 return containing()->IsProcessingImport(); 426 return false; 427 } 428 429 const SourceDir& Scope::GetSourceDir() const { 430 if (!source_dir_.is_null()) 431 return source_dir_; 432 if (containing()) 433 return containing()->GetSourceDir(); 434 return source_dir_; 435 } 436 437 Scope::ItemVector* Scope::GetItemCollector() { 438 if (item_collector_) 439 return item_collector_; 440 if (mutable_containing()) 441 return mutable_containing()->GetItemCollector(); 442 return NULL; 443 } 444 445 void Scope::SetProperty(const void* key, void* value) { 446 if (!value) { 447 DCHECK(properties_.find(key) != properties_.end()); 448 properties_.erase(key); 449 } else { 450 properties_[key] = value; 451 } 452 } 453 454 void* Scope::GetProperty(const void* key, const Scope** found_on_scope) const { 455 PropertyMap::const_iterator found = properties_.find(key); 456 if (found != properties_.end()) { 457 if (found_on_scope) 458 *found_on_scope = this; 459 return found->second; 460 } 461 if (containing()) 462 return containing()->GetProperty(key, found_on_scope); 463 return NULL; 464 } 465 466 void Scope::AddProvider(ProgrammaticProvider* p) { 467 programmatic_providers_.insert(p); 468 } 469 470 void Scope::RemoveProvider(ProgrammaticProvider* p) { 471 DCHECK(programmatic_providers_.find(p) != programmatic_providers_.end()); 472 programmatic_providers_.erase(p); 473 } 474