mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-24 14:26:09 +03:00
243 lines
9.3 KiB
C++
243 lines
9.3 KiB
C++
|
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
|
||
|
#include "tools/gn/err.h"
|
||
|
#include "tools/gn/functions.h"
|
||
|
#include "tools/gn/parse_tree.h"
|
||
|
#include "tools/gn/scope.h"
|
||
|
|
||
|
namespace functions {
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
void ForwardAllValues(const FunctionCallNode* function,
|
||
|
Scope* source,
|
||
|
Scope* dest,
|
||
|
const std::set<std::string>& exclusion_set,
|
||
|
Err* err) {
|
||
|
Scope::MergeOptions options;
|
||
|
// This function needs to clobber existing for it to be useful. It will be
|
||
|
// called in a template to forward all values, but there will be some
|
||
|
// default stuff like configs set up in both scopes, so it would always
|
||
|
// fail if it didn't clobber.
|
||
|
options.clobber_existing = true;
|
||
|
options.skip_private_vars = true;
|
||
|
options.mark_dest_used = false;
|
||
|
options.excluded_values = exclusion_set;
|
||
|
source->NonRecursiveMergeTo(dest, options, function,
|
||
|
"source scope", err);
|
||
|
source->MarkAllUsed();
|
||
|
}
|
||
|
|
||
|
void ForwardValuesFromList(Scope* source,
|
||
|
Scope* dest,
|
||
|
const std::vector<Value>& list,
|
||
|
const std::set<std::string>& exclusion_set,
|
||
|
Err* err) {
|
||
|
for (const Value& cur : list) {
|
||
|
if (!cur.VerifyTypeIs(Value::STRING, err))
|
||
|
return;
|
||
|
if (exclusion_set.find(cur.string_value()) != exclusion_set.end())
|
||
|
continue;
|
||
|
const Value* value = source->GetValue(cur.string_value(), true);
|
||
|
if (value) {
|
||
|
// Use the storage key for the original value rather than the string in
|
||
|
// "cur" because "cur" is a temporary that will be deleted, and Scopes
|
||
|
// expect a persistent StringPiece (it won't copy). Not doing this will
|
||
|
// lead the scope's key to point to invalid memory after this returns.
|
||
|
base::StringPiece storage_key = source->GetStorageKey(cur.string_value());
|
||
|
if (storage_key.empty()) {
|
||
|
// Programmatic value, don't allow copying.
|
||
|
*err = Err(cur, "This value can't be forwarded.",
|
||
|
"The variable \"" + cur.string_value() + "\" is a built-in.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Don't allow clobbering existing values.
|
||
|
const Value* existing_value = dest->GetValue(storage_key);
|
||
|
if (existing_value) {
|
||
|
*err = Err(cur, "Clobbering existing value.",
|
||
|
"The current scope already defines a value \"" +
|
||
|
cur.string_value() + "\".\nforward_variables_from() won't clobber "
|
||
|
"existing values. If you want to\nmerge lists, you'll need to "
|
||
|
"do this explicitly.");
|
||
|
err->AppendSubErr(Err(*existing_value, "value being clobbered."));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Keep the origin information from the original value. The normal
|
||
|
// usage is for this to be used in a template, and if there's an error,
|
||
|
// the user expects to see the line where they set the variable
|
||
|
// blamed, rather than a template call to forward_variables_from().
|
||
|
dest->SetValue(storage_key, *value, value->origin());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
const char kForwardVariablesFrom[] = "forward_variables_from";
|
||
|
const char kForwardVariablesFrom_HelpShort[] =
|
||
|
"forward_variables_from: Copies variables from a different scope.";
|
||
|
const char kForwardVariablesFrom_Help[] =
|
||
|
R"(forward_variables_from: Copies variables from a different scope.
|
||
|
|
||
|
forward_variables_from(from_scope, variable_list_or_star,
|
||
|
variable_to_not_forward_list = [])
|
||
|
|
||
|
Copies the given variables from the given scope to the local scope if they
|
||
|
exist. This is normally used in the context of templates to use the values of
|
||
|
variables defined in the template invocation to a template-defined target.
|
||
|
|
||
|
The variables in the given variable_list will be copied if they exist in the
|
||
|
given scope or any enclosing scope. If they do not exist, nothing will happen
|
||
|
and they be left undefined in the current scope.
|
||
|
|
||
|
As a special case, if the variable_list is a string with the value of "*",
|
||
|
all variables from the given scope will be copied. "*" only copies variables
|
||
|
set directly on the from_scope, not enclosing ones. Otherwise it would
|
||
|
duplicate all global variables.
|
||
|
|
||
|
When an explicit list of variables is supplied, if the variable exists in the
|
||
|
current (destination) scope already, an error will be thrown. If "*" is
|
||
|
specified, variables in the current scope will be clobbered (the latter is
|
||
|
important because most targets have an implicit configs list, which means it
|
||
|
wouldn't work at all if it didn't clobber).
|
||
|
|
||
|
The sources assignment filter (see "gn help "
|
||
|
"set_sources_assignment_filter")
|
||
|
is never applied by this function. It's assumed than any desired filtering
|
||
|
was already done when sources was set on the from_scope.
|
||
|
|
||
|
If variables_to_not_forward_list is non-empty, then it must contains a list
|
||
|
of variable names that will not be forwarded. This is mostly useful when
|
||
|
variable_list_or_star has a value of "*".
|
||
|
|
||
|
Examples
|
||
|
|
||
|
# This is a common action template. It would invoke a script with some given
|
||
|
# parameters, and wants to use the various types of deps and the visibility
|
||
|
# from the invoker if it's defined. It also injects an additional dependency
|
||
|
# to all targets.
|
||
|
template("my_test") {
|
||
|
action(target_name) {
|
||
|
forward_variables_from(invoker, [ "data_deps", "deps",
|
||
|
"public_deps", "visibility" "
|
||
|
"])
|
||
|
# Add our test code to the dependencies.
|
||
|
# "deps" may or may not be defined at this point.
|
||
|
if (defined(deps)) {
|
||
|
deps += [ "//tools/doom_melon" ]
|
||
|
} else {
|
||
|
deps = [ "//tools/doom_melon" ]
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# This is a template around either a target whose type depends on a global
|
||
|
# variable. It forwards all values from the invoker.
|
||
|
template("my_wrapper") {
|
||
|
target(my_wrapper_target_type, target_name) {
|
||
|
forward_variables_from(invoker, "*")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# A template that wraps another. It adds behavior based on one
|
||
|
# variable, and forwards all others to the nested target.
|
||
|
template("my_ios_test_app") {
|
||
|
ios_test_app(target_name) {
|
||
|
forward_variables_from(invoker, "*", ["test_bundle_name"])
|
||
|
if (!defined(extra_substitutions)) {
|
||
|
extra_substitutions = []
|
||
|
}
|
||
|
extra_substitutions += [ "BUNDLE_ID_TEST_NAME=$test_bundle_name" ]
|
||
|
}
|
||
|
}
|
||
|
)";
|
||
|
|
||
|
// This function takes a ListNode rather than a resolved vector of values
|
||
|
// both avoid copying the potentially-large source scope, and so the variables
|
||
|
// in the source scope can be marked as used.
|
||
|
Value RunForwardVariablesFrom(Scope* scope,
|
||
|
const FunctionCallNode* function,
|
||
|
const ListNode* args_list,
|
||
|
Err* err) {
|
||
|
const auto& args_vector = args_list->contents();
|
||
|
if (args_vector.size() != 2 && args_vector.size() != 3) {
|
||
|
*err = Err(function, "Wrong number of arguments.",
|
||
|
"Expecting two or three arguments.");
|
||
|
return Value();
|
||
|
}
|
||
|
|
||
|
Value* value = nullptr; // Value to use, may point to result_value.
|
||
|
Value result_value; // Storage for the "evaluate" case.
|
||
|
const IdentifierNode* identifier = args_vector[0]->AsIdentifier();
|
||
|
if (identifier) {
|
||
|
// Optimize the common case where the input scope is an identifier. This
|
||
|
// prevents a copy of a potentially large Scope object.
|
||
|
value = scope->GetMutableValue(identifier->value().value(),
|
||
|
Scope::SEARCH_NESTED, true);
|
||
|
if (!value) {
|
||
|
*err = Err(identifier, "Undefined identifier.");
|
||
|
return Value();
|
||
|
}
|
||
|
} else {
|
||
|
// Non-optimized case, just evaluate the argument.
|
||
|
result_value = args_vector[0]->Execute(scope, err);
|
||
|
if (err->has_error())
|
||
|
return Value();
|
||
|
value = &result_value;
|
||
|
}
|
||
|
|
||
|
// Extract the source scope.
|
||
|
if (!value->VerifyTypeIs(Value::SCOPE, err))
|
||
|
return Value();
|
||
|
Scope* source = value->scope_value();
|
||
|
|
||
|
// Extract the exclusion list if defined.
|
||
|
std::set<std::string> exclusion_set;
|
||
|
if (args_vector.size() == 3) {
|
||
|
Value exclusion_value = args_vector[2]->Execute(scope, err);
|
||
|
if (err->has_error())
|
||
|
return Value();
|
||
|
|
||
|
if (exclusion_value.type() != Value::LIST) {
|
||
|
*err = Err(exclusion_value, "Not a valid list of variables to exclude.",
|
||
|
"Expecting a list of strings.");
|
||
|
return Value();
|
||
|
}
|
||
|
|
||
|
for (const Value& cur : exclusion_value.list_value()) {
|
||
|
if (!cur.VerifyTypeIs(Value::STRING, err))
|
||
|
return Value();
|
||
|
|
||
|
exclusion_set.insert(cur.string_value());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Extract the list. If all_values is not set, the what_value will be a list.
|
||
|
Value what_value = args_vector[1]->Execute(scope, err);
|
||
|
if (err->has_error())
|
||
|
return Value();
|
||
|
if (what_value.type() == Value::STRING) {
|
||
|
if (what_value.string_value() == "*") {
|
||
|
ForwardAllValues(function, source, scope, exclusion_set, err);
|
||
|
return Value();
|
||
|
}
|
||
|
} else {
|
||
|
if (what_value.type() == Value::LIST) {
|
||
|
ForwardValuesFromList(source, scope, what_value.list_value(),
|
||
|
exclusion_set, err);
|
||
|
return Value();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Not the right type of argument.
|
||
|
*err = Err(what_value, "Not a valid list of variables to copy.",
|
||
|
"Expecting either the string \"*\" or a list of strings.");
|
||
|
return Value();
|
||
|
}
|
||
|
|
||
|
} // namespace functions
|