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