| 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 |