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