const unsigned kProcessingBuildConfigFlag = 1;
const unsigned kProcessingImportFlag = 2;
+// Returns true if this variable name should be considered private. Private
+// values start with an underscore, and are not imported from "gni" files
+// when processing an import.
+bool IsPrivateVar(const base::StringPiece& name) {
+ return name.empty() || name[0] == '_';
+}
+
} // namespace
Scope::Scope(const Settings* settings)
: const_containing_(NULL),
mutable_containing_(NULL),
settings_(settings),
- mode_flags_(0) {
+ mode_flags_(0),
+ item_collector_(NULL) {
}
Scope::Scope(Scope* parent)
: const_containing_(NULL),
mutable_containing_(parent),
settings_(parent->settings()),
- mode_flags_(0) {
+ mode_flags_(0),
+ item_collector_(NULL) {
}
Scope::Scope(const Scope* parent)
: const_containing_(parent),
mutable_containing_(NULL),
settings_(parent->settings()),
- mode_flags_(0) {
+ mode_flags_(0),
+ item_collector_(NULL) {
}
Scope::~Scope() {
STLDeleteContainerPairSecondPointers(target_defaults_.begin(),
target_defaults_.end());
- STLDeleteContainerPairSecondPointers(templates_.begin(), templates_.end());
}
const Value* Scope::GetValue(const base::StringPiece& ident,
bool counts_as_used) {
// First check for programatically-provided values.
- for (ProviderSet::const_iterator i = programmatic_providers_.begin();
- i != programmatic_providers_.end(); ++i) {
- const Value* v = (*i)->GetProgrammaticValue(ident);
+ for (const auto& provider : programmatic_providers_) {
+ const Value* v = provider->GetProgrammaticValue(ident);
if (v)
return v;
}
return &r.value;
}
-bool Scope::AddTemplate(const std::string& name, scoped_ptr<Template> templ) {
+void Scope::RemoveIdentifier(const base::StringPiece& ident) {
+ RecordMap::iterator found = values_.find(ident);
+ if (found != values_.end())
+ values_.erase(found);
+}
+
+void Scope::RemovePrivateIdentifiers() {
+ // Do it in two phases to avoid mutating while iterating. Our hash map is
+ // currently backed by several different vendor-specific implementations and
+ // I'm not sure if all of them support mutating while iterating. Since this
+ // is not perf-critical, do the safe thing.
+ std::vector<base::StringPiece> to_remove;
+ for (const auto& cur : values_) {
+ if (IsPrivateVar(cur.first))
+ to_remove.push_back(cur.first);
+ }
+
+ for (const auto& cur : to_remove)
+ values_.erase(cur);
+}
+
+bool Scope::AddTemplate(const std::string& name, const Template* templ) {
if (GetTemplate(name))
return false;
- templates_[name] = templ.release();
+ templates_[name] = templ;
return true;
}
const Template* Scope::GetTemplate(const std::string& name) const {
TemplateMap::const_iterator found = templates_.find(name);
if (found != templates_.end())
- return found->second;
+ return found->second.get();
if (containing())
return containing()->GetTemplate(name);
return NULL;
}
bool Scope::CheckForUnusedVars(Err* err) const {
- for (RecordMap::const_iterator i = values_.begin();
- i != values_.end(); ++i) {
- if (!i->second.used) {
- std::string help = "You set the variable \"" + i->first.as_string() +
+ for (const auto& pair : values_) {
+ if (!pair.second.used) {
+ std::string help = "You set the variable \"" + pair.first.as_string() +
"\" here and it was unused before it went\nout of scope.";
- const BinaryOpNode* binary = i->second.value.origin()->AsBinaryOp();
+ const BinaryOpNode* binary = pair.second.value.origin()->AsBinaryOp();
if (binary && binary->op().type() == Token::EQUAL) {
// Make a nicer error message for normal var sets.
*err = Err(binary->left()->GetRange(), "Assignment had no effect.",
help);
} else {
// This will happen for internally-generated variables.
- *err = Err(i->second.value.origin(), "Assignment had no effect.", help);
+ *err = Err(pair.second.value.origin(), "Assignment had no effect.",
+ help);
}
return false;
}
}
void Scope::GetCurrentScopeValues(KeyValueMap* output) const {
- for (RecordMap::const_iterator i = values_.begin(); i != values_.end(); ++i)
- (*output)[i->first] = i->second.value;
+ for (const auto& pair : values_)
+ (*output)[pair.first] = pair.second.value;
}
bool Scope::NonRecursiveMergeTo(Scope* dest,
- bool clobber_existing,
+ const MergeOptions& options,
const ParseNode* node_for_err,
const char* desc_for_err,
Err* err) const {
// Values.
- for (RecordMap::const_iterator i = values_.begin(); i != values_.end(); ++i) {
- const Value& new_value = i->second.value;
- if (!clobber_existing) {
- const Value* existing_value = dest->GetValue(i->first);
+ for (const auto& pair : values_) {
+ if (options.skip_private_vars && IsPrivateVar(pair.first))
+ continue; // Skip this private var.
+
+ const Value& new_value = pair.second.value;
+ if (!options.clobber_existing) {
+ const Value* existing_value = dest->GetValue(pair.first);
if (existing_value && new_value != *existing_value) {
// Value present in both the source and the dest.
std::string desc_string(desc_for_err);
*err = Err(node_for_err, "Value collision.",
- "This " + desc_string + " contains \"" + i->first.as_string() +
+ "This " + desc_string + " contains \"" + pair.first.as_string() +
"\"");
- err->AppendSubErr(Err(i->second.value, "defined here.",
+ err->AppendSubErr(Err(pair.second.value, "defined here.",
"Which would clobber the one in your current scope"));
err->AppendSubErr(Err(*existing_value, "defined here.",
"Executing " + desc_string + " should not conflict with anything "
return false;
}
}
- dest->values_[i->first] = i->second;
+ dest->values_[pair.first] = pair.second;
+
+ if (options.mark_used)
+ dest->MarkUsed(pair.first);
}
// Target defaults are owning pointers.
- for (NamedScopeMap::const_iterator i = target_defaults_.begin();
- i != target_defaults_.end(); ++i) {
- if (!clobber_existing) {
- if (dest->GetTargetDefaults(i->first)) {
+ for (const auto& pair : target_defaults_) {
+ if (!options.clobber_existing) {
+ if (dest->GetTargetDefaults(pair.first)) {
// TODO(brettw) it would be nice to know the origin of a
// set_target_defaults so we can give locations for the colliding target
// defaults.
std::string desc_string(desc_for_err);
*err = Err(node_for_err, "Target defaults collision.",
"This " + desc_string + " contains target defaults for\n"
- "\"" + i->first + "\" which would clobber one for the\n"
+ "\"" + pair.first + "\" which would clobber one for the\n"
"same target type in your current scope. It's unfortunate that I'm "
"too stupid\nto tell you the location of where the target defaults "
"were set. Usually\nthis happens in the BUILDCONFIG.gn file.");
}
// Be careful to delete any pointer we're about to clobber.
- Scope** dest_scope = &dest->target_defaults_[i->first];
+ Scope** dest_scope = &dest->target_defaults_[pair.first];
if (*dest_scope)
delete *dest_scope;
*dest_scope = new Scope(settings_);
- i->second->NonRecursiveMergeTo(*dest_scope, clobber_existing, node_for_err,
- "<SHOULDN'T HAPPEN>", err);
+ pair.second->NonRecursiveMergeTo(*dest_scope, options, node_for_err,
+ "<SHOULDN'T HAPPEN>", err);
}
// Sources assignment filter.
if (sources_assignment_filter_) {
- if (!clobber_existing) {
+ if (!options.clobber_existing) {
if (dest->GetSourcesAssignmentFilter()) {
// Sources assignment filter present in both the source and the dest.
std::string desc_string(desc_for_err);
}
// Templates.
- for (TemplateMap::const_iterator i = templates_.begin();
- i != templates_.end(); ++i) {
- if (!clobber_existing) {
- const Template* existing_template = dest->GetTemplate(i->first);
- if (existing_template) {
- // Rule present in both the source and the dest.
+ for (const auto& pair : templates_) {
+ if (options.skip_private_vars && IsPrivateVar(pair.first))
+ continue; // Skip this private template.
+
+ if (!options.clobber_existing) {
+ const Template* existing_template = dest->GetTemplate(pair.first);
+ // Since templates are refcounted, we can check if it's the same one by
+ // comparing pointers.
+ if (existing_template && pair.second.get() != existing_template) {
+ // Rule present in both the source and the dest, and they're not the
+ // same one.
std::string desc_string(desc_for_err);
*err = Err(node_for_err, "Template collision.",
"This " + desc_string + " contains a template \"" +
- i->first + "\"");
- err->AppendSubErr(Err(i->second->GetDefinitionRange(), "defined here.",
+ pair.first + "\"");
+ err->AppendSubErr(Err(pair.second->GetDefinitionRange(),
+ "defined here.",
"Which would clobber the one in your current scope"));
err->AppendSubErr(Err(existing_template->GetDefinitionRange(),
"defined here.",
}
// Be careful to delete any pointer we're about to clobber.
- const Template** dest_template = &dest->templates_[i->first];
- if (*dest_template)
- delete *dest_template;
- *dest_template = i->second;
+ dest->templates_[pair.first] = pair.second;
}
return true;
result.reset(new Scope(settings_));
}
+ // Want to clobber since we've flattened some nested scopes, and our parent
+ // scope may have a duplicate value set.
+ MergeOptions options;
+ options.clobber_existing = true;
+
// Add in our variables and we're done.
Err err;
- NonRecursiveMergeTo(result.get(), true, NULL, "<SHOULDN'T HAPPEN>", &err);
+ NonRecursiveMergeTo(result.get(), options, NULL, "<SHOULDN'T HAPPEN>", &err);
DCHECK(!err.has_error());
return result.Pass();
}
return source_dir_;
}
+Scope::ItemVector* Scope::GetItemCollector() {
+ if (item_collector_)
+ return item_collector_;
+ if (mutable_containing())
+ return mutable_containing()->GetItemCollector();
+ return NULL;
+}
+
void Scope::SetProperty(const void* key, void* value) {
if (!value) {
DCHECK(properties_.find(key) != properties_.end());