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