GN: Use the correct defaults for templates invoked via target().
Previously calling
target("foo", "bar")
where "foo" is a template applied the defaults for the function named "target"
(since this is the function call) rather than "foo".
This change properly applies the defaults for "foo" in this case.
BUG=624564
Review-Url: https://codereview.chromium.org/2148093002
Cr-Original-Commit-Position: refs/heads/master@{#405547}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: af92718f5526ce94ea8fcb4118f850fb9a7517b3
diff --git a/tools/gn/functions.cc b/tools/gn/functions.cc
index 0a00c9c..0102bd7 100644
--- a/tools/gn/functions.cc
+++ b/tools/gn/functions.cc
@@ -1036,13 +1036,14 @@
function_map.find(name.value());
if (found_function == function_map.end()) {
// No built-in function matching this, check for a template.
- const Template* templ =
- scope->GetTemplate(function->function().value().as_string());
+ std::string template_name = function->function().value().as_string();
+ const Template* templ = scope->GetTemplate(template_name);
if (templ) {
Value args = args_list->Execute(scope, err);
if (err->has_error())
return Value();
- return templ->Invoke(scope, function, args.list_value(), block, err);
+ return templ->Invoke(scope, function, template_name, args.list_value(),
+ block, err);
}
*err = Err(name, "Unknown function.");
diff --git a/tools/gn/functions_target.cc b/tools/gn/functions_target.cc
index 4e162d5..8aa7f93 100644
--- a/tools/gn/functions_target.cc
+++ b/tools/gn/functions_target.cc
@@ -773,7 +773,7 @@
// Run a template if it is one.
const Template* templ = scope->GetTemplate(target_type);
if (templ)
- return templ->Invoke(scope, function, sub_args, block, err);
+ return templ->Invoke(scope, function, target_type, sub_args, block, err);
// Otherwise, assume the target is a built-in target type.
return ExecuteGenericTarget(target_type.c_str(), scope, function, sub_args,
diff --git a/tools/gn/functions_target_unittest.cc b/tools/gn/functions_target_unittest.cc
index a7a0de9..f4eeb38 100644
--- a/tools/gn/functions_target_unittest.cc
+++ b/tools/gn/functions_target_unittest.cc
@@ -36,3 +36,37 @@
source_set_input.parsed()->Execute(setup.scope(), &err);
ASSERT_TRUE(err.has_error());
}
+
+// Checks that the defaults applied to a template invoked by target() use
+// the name of the template, rather than the string "target" (which is the
+// name of the actual function being called).
+TEST(FunctionsTarget, TemplateDefaults) {
+ Scheduler scheduler;
+ TestWithScope setup;
+
+ // The target generator needs a place to put the targets or it will fail.
+ Scope::ItemVector item_collector;
+ setup.scope()->set_item_collector(&item_collector);
+
+ // Test a good one first.
+ TestParseInput good_input(
+ // Make a template with defaults set.
+ "template(\"my_templ\") {\n"
+ " source_set(target_name) {\n"
+ " forward_variables_from(invoker, \"*\")\n"
+ " }\n"
+ "}\n"
+ "set_defaults(\"my_templ\") {\n"
+ " default_value = 1\n"
+ "}\n"
+
+ // Invoke the template with target(). This will fail to execute if the
+ // defaults were not set properly, because "default_value" won't exist.
+ "target(\"my_templ\", \"foo\") {\n"
+ " print(default_value)\n"
+ "}\n");
+ ASSERT_FALSE(good_input.has_error());
+ Err err;
+ good_input.parsed()->Execute(setup.scope(), &err);
+ ASSERT_FALSE(err.has_error()) << err.message();
+}
diff --git a/tools/gn/template.cc b/tools/gn/template.cc
index 8b8ae69..3c4d76d 100644
--- a/tools/gn/template.cc
+++ b/tools/gn/template.cc
@@ -26,6 +26,7 @@
Value Template::Invoke(Scope* scope,
const FunctionCallNode* invocation,
+ const std::string& template_name,
const std::vector<Value>& args,
BlockNode* block,
Err* err) const {
@@ -37,8 +38,7 @@
// First run the invocation's block. Need to allocate the scope on the heap
// so we can pass ownership to the template.
std::unique_ptr<Scope> invocation_scope(new Scope(scope));
- if (!FillTargetBlockScope(scope, invocation,
- invocation->function().value().as_string(),
+ if (!FillTargetBlockScope(scope, invocation, template_name,
block, args, invocation_scope.get(), err))
return Value();
diff --git a/tools/gn/template.h b/tools/gn/template.h
index a79d82f..da5a1a4 100644
--- a/tools/gn/template.h
+++ b/tools/gn/template.h
@@ -33,9 +33,12 @@
Template(std::unique_ptr<Scope> closure, const FunctionCallNode* def);
// Invoke the template. The values correspond to the state of the code
- // invoking the template.
+ // invoking the template. The template name needs to be supplied since the
+ // template object itself doesn't know what name the calling code is using
+ // to refer to it (this is used to set defaults).
Value Invoke(Scope* scope,
const FunctionCallNode* invocation,
+ const std::string& template_name,
const std::vector<Value>& args,
BlockNode* block,
Err* err) const;