Home | History | Annotate | Download | only in gn
      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