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 if (existing_template) { 311 // Rule present in both the source and the dest. 312 std::string desc_string(desc_for_err); 313 *err = Err(node_for_err, "Template collision.", 314 "This " + desc_string + " contains a template \"" + 315 i->first + "\""); 316 err->AppendSubErr(Err(i->second->GetDefinitionRange(), "defined here.", 317 "Which would clobber the one in your current scope")); 318 err->AppendSubErr(Err(existing_template->GetDefinitionRange(), 319 "defined here.", 320 "Executing " + desc_string + " should not conflict with anything " 321 "in the current\nscope.")); 322 return false; 323 } 324 } 325 326 // Be careful to delete any pointer we're about to clobber. 327 dest->templates_[i->first] = i->second; 328 } 329 330 return true; 331 } 332 333 scoped_ptr<Scope> Scope::MakeClosure() const { 334 scoped_ptr<Scope> result; 335 if (const_containing_) { 336 // We reached the top of the mutable scope stack. The result scope just 337 // references the const scope (which will never change). 338 result.reset(new Scope(const_containing_)); 339 } else if (mutable_containing_) { 340 // There are more nested mutable scopes. Recursively go up the stack to 341 // get the closure. 342 result = mutable_containing_->MakeClosure(); 343 } else { 344 // This is a standalone scope, just copy it. 345 result.reset(new Scope(settings_)); 346 } 347 348 // Want to clobber since we've flattened some nested scopes, and our parent 349 // scope may have a duplicate value set. 350 MergeOptions options; 351 options.clobber_existing = true; 352 353 // Add in our variables and we're done. 354 Err err; 355 NonRecursiveMergeTo(result.get(), options, NULL, "<SHOULDN'T HAPPEN>", &err); 356 DCHECK(!err.has_error()); 357 return result.Pass(); 358 } 359 360 Scope* Scope::MakeTargetDefaults(const std::string& target_type) { 361 if (GetTargetDefaults(target_type)) 362 return NULL; 363 364 Scope** dest = &target_defaults_[target_type]; 365 if (*dest) { 366 NOTREACHED(); // Already set. 367 return *dest; 368 } 369 *dest = new Scope(settings_); 370 return *dest; 371 } 372 373 const Scope* Scope::GetTargetDefaults(const std::string& target_type) const { 374 NamedScopeMap::const_iterator found = target_defaults_.find(target_type); 375 if (found != target_defaults_.end()) 376 return found->second; 377 if (containing()) 378 return containing()->GetTargetDefaults(target_type); 379 return NULL; 380 } 381 382 const PatternList* Scope::GetSourcesAssignmentFilter() const { 383 if (sources_assignment_filter_) 384 return sources_assignment_filter_.get(); 385 if (containing()) 386 return containing()->GetSourcesAssignmentFilter(); 387 return NULL; 388 } 389 390 void Scope::SetProcessingBuildConfig() { 391 DCHECK((mode_flags_ & kProcessingBuildConfigFlag) == 0); 392 mode_flags_ |= kProcessingBuildConfigFlag; 393 } 394 395 void Scope::ClearProcessingBuildConfig() { 396 DCHECK(mode_flags_ & kProcessingBuildConfigFlag); 397 mode_flags_ &= ~(kProcessingBuildConfigFlag); 398 } 399 400 bool Scope::IsProcessingBuildConfig() const { 401 if (mode_flags_ & kProcessingBuildConfigFlag) 402 return true; 403 if (containing()) 404 return containing()->IsProcessingBuildConfig(); 405 return false; 406 } 407 408 void Scope::SetProcessingImport() { 409 DCHECK((mode_flags_ & kProcessingImportFlag) == 0); 410 mode_flags_ |= kProcessingImportFlag; 411 } 412 413 void Scope::ClearProcessingImport() { 414 DCHECK(mode_flags_ & kProcessingImportFlag); 415 mode_flags_ &= ~(kProcessingImportFlag); 416 } 417 418 bool Scope::IsProcessingImport() const { 419 if (mode_flags_ & kProcessingImportFlag) 420 return true; 421 if (containing()) 422 return containing()->IsProcessingImport(); 423 return false; 424 } 425 426 const SourceDir& Scope::GetSourceDir() const { 427 if (!source_dir_.is_null()) 428 return source_dir_; 429 if (containing()) 430 return containing()->GetSourceDir(); 431 return source_dir_; 432 } 433 434 Scope::ItemVector* Scope::GetItemCollector() { 435 if (item_collector_) 436 return item_collector_; 437 if (mutable_containing()) 438 return mutable_containing()->GetItemCollector(); 439 return NULL; 440 } 441 442 void Scope::SetProperty(const void* key, void* value) { 443 if (!value) { 444 DCHECK(properties_.find(key) != properties_.end()); 445 properties_.erase(key); 446 } else { 447 properties_[key] = value; 448 } 449 } 450 451 void* Scope::GetProperty(const void* key, const Scope** found_on_scope) const { 452 PropertyMap::const_iterator found = properties_.find(key); 453 if (found != properties_.end()) { 454 if (found_on_scope) 455 *found_on_scope = this; 456 return found->second; 457 } 458 if (containing()) 459 return containing()->GetProperty(key, found_on_scope); 460 return NULL; 461 } 462 463 void Scope::AddProvider(ProgrammaticProvider* p) { 464 programmatic_providers_.insert(p); 465 } 466 467 void Scope::RemoveProvider(ProgrammaticProvider* p) { 468 DCHECK(programmatic_providers_.find(p) != programmatic_providers_.end()); 469 programmatic_providers_.erase(p); 470 } 471