OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/gn/template.h" | 5 #include "tools/gn/template.h" |
6 | 6 |
7 #include "tools/gn/err.h" | 7 #include "tools/gn/err.h" |
8 #include "tools/gn/functions.h" | 8 #include "tools/gn/functions.h" |
9 #include "tools/gn/parse_tree.h" | 9 #include "tools/gn/parse_tree.h" |
10 #include "tools/gn/scope.h" | 10 #include "tools/gn/scope.h" |
(...skipping 21 matching lines...) Expand all Loading... |
32 Value Template::Invoke(Scope* scope, | 32 Value Template::Invoke(Scope* scope, |
33 const FunctionCallNode* invocation, | 33 const FunctionCallNode* invocation, |
34 const std::vector<Value>& args, | 34 const std::vector<Value>& args, |
35 BlockNode* block, | 35 BlockNode* block, |
36 Err* err) const { | 36 Err* err) const { |
37 // Don't allow templates to be executed from imported files. Imports are for | 37 // Don't allow templates to be executed from imported files. Imports are for |
38 // simple values only. | 38 // simple values only. |
39 if (!EnsureNotProcessingImport(invocation, scope, err)) | 39 if (!EnsureNotProcessingImport(invocation, scope, err)) |
40 return Value(); | 40 return Value(); |
41 | 41 |
42 // First run the invocation's block. | 42 // First run the invocation's block. Need to allocate the scope on the heap |
43 Scope invocation_scope(scope); | 43 // so we can pass ownership to the template. |
| 44 scoped_ptr<Scope> invocation_scope(new Scope(scope)); |
44 if (!FillTargetBlockScope(scope, invocation, | 45 if (!FillTargetBlockScope(scope, invocation, |
45 invocation->function().value().as_string(), | 46 invocation->function().value().as_string(), |
46 block, args, &invocation_scope, err)) | 47 block, args, invocation_scope.get(), err)) |
47 return Value(); | 48 return Value(); |
48 block->ExecuteBlockInScope(&invocation_scope, err); | 49 block->ExecuteBlockInScope(invocation_scope.get(), err); |
49 if (err->has_error()) | 50 if (err->has_error()) |
50 return Value(); | 51 return Value(); |
51 | 52 |
52 // Set up the scope to run the template. This should be dependent on the | 53 // Set up the scope to run the template. This should be dependent on the |
53 // closure, but have the "invoker" and "target_name" values injected, and the | 54 // closure, but have the "invoker" and "target_name" values injected, and the |
54 // current dir matching the invoker. | 55 // current dir matching the invoker. We jump through some hoops to avoid |
| 56 // copying the invocation scope when setting it in the template scope (since |
| 57 // the invocation scope may have large lists of source files in it and could |
| 58 // be expensive to copy). |
| 59 // |
| 60 // Scope.SetValue will copy the value which will in turn copy the scope, but |
| 61 // if we instead create a value and then set the scope on it, the copy can |
| 62 // be avoided. |
55 Scope template_scope(closure_.get()); | 63 Scope template_scope(closure_.get()); |
56 template_scope.SetValue("invoker", Value(NULL, &invocation_scope), | 64 const char kInvoker[] = "invoker"; |
| 65 template_scope.SetValue(kInvoker, Value(NULL, scoped_ptr<Scope>()), |
57 invocation); | 66 invocation); |
| 67 Value* invoker_value = template_scope.GetMutableValue(kInvoker, false); |
| 68 invoker_value->SetScopeValue(invocation_scope.Pass()); |
58 template_scope.set_source_dir(scope->GetSourceDir()); | 69 template_scope.set_source_dir(scope->GetSourceDir()); |
59 | 70 |
60 const base::StringPiece target_name("target_name"); | 71 const base::StringPiece target_name("target_name"); |
61 template_scope.SetValue(target_name, | 72 template_scope.SetValue(target_name, |
62 Value(invocation, args[0].string_value()), | 73 Value(invocation, args[0].string_value()), |
63 invocation); | 74 invocation); |
64 | 75 |
65 // Run the template code. Don't check for unused variables since the | 76 // Run the template code. Don't check for unused variables since the |
66 // template could be executed in many different ways and it could be that | 77 // template could be executed in many different ways and it could be that |
67 // not all executions use all values in the closure. | 78 // not all executions use all values in the closure. |
68 return definition_->block()->ExecuteBlockInScope(&template_scope, err); | 79 Value result = |
| 80 definition_->block()->ExecuteBlockInScope(&template_scope, err); |
| 81 |
| 82 // Check for unused variables in the invocation scope. This will find typos |
| 83 // of things the caller meant to pass to the template but the template didn't |
| 84 // read out. |
| 85 // |
| 86 // This is a bit tricky because it's theoretically possible for the template |
| 87 // to overwrite the value of "invoker" and free the Scope owned by the |
| 88 // value. So we need to look it up again and don't do anything if it doesn't |
| 89 // exist. |
| 90 invoker_value = template_scope.GetMutableValue(kInvoker, false); |
| 91 if (invoker_value && invoker_value->type() == Value::SCOPE) { |
| 92 if (!invoker_value->scope_value()->CheckForUnusedVars(err)) |
| 93 return Value(); |
| 94 } |
| 95 |
| 96 // Check for unused variables in the template itself. |
| 97 if (!template_scope.CheckForUnusedVars(err)) |
| 98 return Value(); |
| 99 |
| 100 return result; |
69 } | 101 } |
70 | 102 |
71 LocationRange Template::GetDefinitionRange() const { | 103 LocationRange Template::GetDefinitionRange() const { |
72 return definition_->GetRange(); | 104 return definition_->GetRange(); |
73 } | 105 } |
OLD | NEW |