1 // Copyright 2014 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 "gn/template.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "gn/err.h"
11 #include "gn/functions.h"
12 #include "gn/parse_tree.h"
13 #include "gn/scope.h"
14 #include "gn/scope_per_file_provider.h"
15 #include "gn/value.h"
16 #include "gn/variables.h"
17
Template(const Scope * scope,const FunctionCallNode * def)18 Template::Template(const Scope* scope, const FunctionCallNode* def)
19 : closure_(scope->MakeClosure()), definition_(def) {}
20
Template(std::unique_ptr<Scope> scope,const FunctionCallNode * def)21 Template::Template(std::unique_ptr<Scope> scope, const FunctionCallNode* def)
22 : closure_(std::move(scope)), definition_(def) {}
23
24 Template::~Template() = default;
25
Invoke(Scope * scope,const FunctionCallNode * invocation,const std::string & template_name,const std::vector<Value> & args,BlockNode * block,Err * err) const26 Value Template::Invoke(Scope* scope,
27 const FunctionCallNode* invocation,
28 const std::string& template_name,
29 const std::vector<Value>& args,
30 BlockNode* block,
31 Err* err) const {
32 // Don't allow templates to be executed from imported files. Imports are for
33 // simple values only.
34 if (!EnsureNotProcessingImport(invocation, scope, err))
35 return Value();
36
37 // First run the invocation's block. Need to allocate the scope on the heap
38 // so we can pass ownership to the template.
39 std::unique_ptr<Scope> invocation_scope = std::make_unique<Scope>(scope);
40 if (!FillTargetBlockScope(scope, invocation, template_name, block, args,
41 invocation_scope.get(), err))
42 return Value();
43
44 {
45 // Don't allow the block of the template invocation to include other
46 // targets configs, or template invocations. This must only be applied
47 // to the invoker's block rather than the whole function because the
48 // template execution itself must be able to define targets, etc.
49 NonNestableBlock non_nestable(scope, invocation, "template invocation");
50 if (!non_nestable.Enter(err))
51 return Value();
52
53 block->Execute(invocation_scope.get(), err);
54 if (err->has_error())
55 return Value();
56 }
57
58 // Set up the scope to run the template and set the current directory for the
59 // template (which ScopePerFileProvider uses to base the target-related
60 // variables target_gen_dir and target_out_dir on) to be that of the invoker.
61 // This way, files don't have to be rebased and target_*_dir works the way
62 // people expect (otherwise its to easy to be putting generated files in the
63 // gen dir corresponding to an imported file).
64 Scope template_scope(closure_.get());
65 template_scope.set_source_dir(scope->GetSourceDir());
66
67 // Propagate build dependency files from invoker scope (template scope already
68 // propagated via parent scope).
69 template_scope.AddBuildDependencyFiles(
70 invocation_scope->build_dependency_files());
71
72 ScopePerFileProvider per_file_provider(&template_scope, true);
73
74 // Targets defined in the template go in the collector for the invoking file.
75 template_scope.set_item_collector(scope->GetItemCollector());
76
77 // We jump through some hoops to avoid copying the invocation scope when
78 // setting it in the template scope (since the invocation scope may have
79 // large lists of source files in it and could be expensive to copy).
80 //
81 // Scope.SetValue will copy the value which will in turn copy the scope, but
82 // if we instead create a value and then set the scope on it, the copy can
83 // be avoided.
84 template_scope.SetValue(variables::kInvoker,
85 Value(nullptr, std::unique_ptr<Scope>()), invocation);
86 Value* invoker_value = template_scope.GetMutableValue(
87 variables::kInvoker, Scope::SEARCH_NESTED, false);
88 invoker_value->SetScopeValue(std::move(invocation_scope));
89 template_scope.set_source_dir(scope->GetSourceDir());
90
91 const std::string_view target_name(variables::kTargetName);
92 template_scope.SetValue(
93 target_name, Value(invocation, args[0].string_value()), invocation);
94
95 // Actually run the template code.
96 Value result = definition_->block()->Execute(&template_scope, err);
97 if (err->has_error()) {
98 // If there was an error, append the caller location so the error message
99 // displays a stack trace of how it got here.
100 err->AppendSubErr(Err(invocation, "whence it was called."));
101 return Value();
102 }
103
104 // Check for unused variables in the invocation scope. This will find typos
105 // of things the caller meant to pass to the template but the template didn't
106 // read out.
107 //
108 // This is a bit tricky because it's theoretically possible for the template
109 // to overwrite the value of "invoker" and free the Scope owned by the
110 // value. So we need to look it up again and don't do anything if it doesn't
111 // exist.
112 invoker_value = template_scope.GetMutableValue(variables::kInvoker,
113 Scope::SEARCH_NESTED, false);
114 if (invoker_value && invoker_value->type() == Value::SCOPE) {
115 if (!invoker_value->scope_value()->CheckForUnusedVars(err))
116 return Value();
117 }
118
119 // Check for unused variables in the template itself.
120 if (!template_scope.CheckForUnusedVars(err))
121 return Value();
122
123 return result;
124 }
125
GetDefinitionRange() const126 LocationRange Template::GetDefinitionRange() const {
127 return definition_->GetRange();
128 }
129