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 } 373