Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/operators.h" | 5 #include "tools/gn/operators.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <algorithm> | 8 #include <algorithm> |
| 9 | 9 |
| 10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 202 } | 202 } |
| 203 | 203 |
| 204 void ValueDestination::MakeUndefinedIdentifierForModifyError(Err* err) { | 204 void ValueDestination::MakeUndefinedIdentifierForModifyError(Err* err) { |
| 205 // When Init() succeeds, the base of any accessor has already been resolved | 205 // When Init() succeeds, the base of any accessor has already been resolved |
| 206 // and that list indices are in-range. This means any undefined identifiers | 206 // and that list indices are in-range. This means any undefined identifiers |
| 207 // are for scope accesses. | 207 // are for scope accesses. |
| 208 DCHECK(type_ == SCOPE); | 208 DCHECK(type_ == SCOPE); |
| 209 *err = Err(*name_token_, "Undefined identifier."); | 209 *err = Err(*name_token_, "Undefined identifier."); |
| 210 } | 210 } |
| 211 | 211 |
| 212 // Computes an error message for overwriting a nonempty list/scope with another. | |
| 213 Err MakeOverwriteError(const BinaryOpNode* op_node, | |
| 214 const Value& old_value) { | |
| 215 std::string type_name; | |
| 216 std::string empty_def; | |
| 217 | |
| 218 if (old_value.type() == Value::LIST) { | |
| 219 type_name = "list"; | |
| 220 empty_def = "[]"; | |
| 221 } else if (old_value.type() == Value::SCOPE) { | |
| 222 type_name = "scope"; | |
| 223 empty_def = "{}"; | |
| 224 } else { | |
| 225 NOTREACHED(); | |
| 226 } | |
| 227 | |
| 228 Err result(op_node->left()->GetRange(), | |
| 229 "Replacing nonempty " + type_name + ".", | |
| 230 "This overwrites a previously-defined nonempty " + type_name + | |
| 231 "with another nonempty " + type_name + "."); | |
| 232 result.AppendSubErr(Err(old_value, "for previous definition", | |
| 233 "Did you mean to append/modify instead? If you really want to overwrite, " | |
| 234 "do:\n" | |
| 235 " foo = " + empty_def + "\nbefore reassigning.")); | |
| 236 return result; | |
| 237 } | |
| 238 | |
| 212 // ----------------------------------------------------------------------------- | 239 // ----------------------------------------------------------------------------- |
| 213 | 240 |
| 214 Err MakeIncompatibleTypeError(const BinaryOpNode* op_node, | 241 Err MakeIncompatibleTypeError(const BinaryOpNode* op_node, |
| 215 const Value& left, | 242 const Value& left, |
| 216 const Value& right) { | 243 const Value& right) { |
| 217 std::string msg = | 244 std::string msg = |
| 218 std::string("You can't do <") + Value::DescribeType(left.type()) + "> " + | 245 std::string("You can't do <") + Value::DescribeType(left.type()) + "> " + |
| 219 op_node->op().value().as_string() + | 246 op_node->op().value().as_string() + |
| 220 " <" + Value::DescribeType(right.type()) + ">."; | 247 " <" + Value::DescribeType(right.type()) + ">."; |
| 221 if (left.type() == Value::LIST) { | 248 if (left.type() == Value::LIST) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 290 | 317 |
| 291 // We return a null value from this rather than the result of doing the append. | 318 // We return a null value from this rather than the result of doing the append. |
| 292 // See ValuePlusEquals for rationale. | 319 // See ValuePlusEquals for rationale. |
| 293 Value ExecuteEquals(Scope* exec_scope, | 320 Value ExecuteEquals(Scope* exec_scope, |
| 294 const BinaryOpNode* op_node, | 321 const BinaryOpNode* op_node, |
| 295 ValueDestination* dest, | 322 ValueDestination* dest, |
| 296 Value right, | 323 Value right, |
| 297 Err* err) { | 324 Err* err) { |
| 298 const Value* old_value = dest->GetExistingValue(); | 325 const Value* old_value = dest->GetExistingValue(); |
| 299 if (old_value) { | 326 if (old_value) { |
| 300 // Throw an error when overwriting a nonempty list with another nonempty | 327 // Check for overwriting nonempty scopes or lists with other nonempty |
| 301 // list item. This is to detect the case where you write | 328 // scopes or lists. This prevents mistakes that clobber a value rather than |
| 302 // defines = ["FOO"] | 329 // appending to it. For cases where a user meant to clear a value, allow |
| 303 // and you overwrote inherited ones, when instead you mean to append: | 330 // overwriting a nonempty list/scope with an empty one, which can then be |
| 304 // defines += ["FOO"] | 331 // modified. |
| 305 if (old_value->type() == Value::LIST && | 332 if (old_value->type() == Value::LIST && right.type() == Value::LIST && |
|
scottmg
2016/08/09 22:20:33
Something else will catch it if I try to overwrite
brettw
2016/08/09 23:00:48
Presumably that will just be wrong. If changing th
| |
| 306 !old_value->list_value().empty() && | 333 !old_value->list_value().empty() && !right.list_value().empty()) { |
| 307 right.type() == Value::LIST && | 334 *err = MakeOverwriteError(op_node, *old_value); |
| 308 !right.list_value().empty()) { | 335 return Value(); |
| 309 *err = Err(op_node->left()->GetRange(), "Replacing nonempty list.", | 336 } else if (old_value->type() == Value::SCOPE && |
| 310 std::string("This overwrites a previously-defined nonempty list ") + | 337 right.type() == Value::SCOPE && |
| 311 "(length " + | 338 old_value->scope_value()->HasValues(Scope::SEARCH_CURRENT) && |
| 312 base::IntToString(static_cast<int>(old_value->list_value().size())) | 339 right.scope_value()->HasValues(Scope::SEARCH_CURRENT)) { |
| 313 + ")."); | 340 *err = MakeOverwriteError(op_node, *old_value); |
| 314 err->AppendSubErr(Err(*old_value, "for previous definition", | |
| 315 "with another one (length " + | |
| 316 base::IntToString(static_cast<int>(right.list_value().size())) + | |
| 317 "). Did you mean " + | |
| 318 "\"+=\" to append instead? If you\nreally want to do this, do\n" | |
| 319 " foo = []\nbefore reassigning.")); | |
| 320 return Value(); | 341 return Value(); |
| 321 } | 342 } |
| 322 } | 343 } |
| 323 if (err->has_error()) | |
| 324 return Value(); | |
| 325 | 344 |
| 326 Value* written_value = dest->SetValue(std::move(right), op_node->right()); | 345 Value* written_value = dest->SetValue(std::move(right), op_node->right()); |
| 327 | 346 |
| 328 // Optionally apply the assignment filter in-place. | 347 // Optionally apply the assignment filter in-place. |
| 329 const PatternList* filter = dest->GetAssignmentFilter(exec_scope); | 348 const PatternList* filter = dest->GetAssignmentFilter(exec_scope); |
| 330 if (filter) { | 349 if (filter) { |
| 331 std::vector<Value>& list_value = written_value->list_value(); | 350 std::vector<Value>& list_value = written_value->list_value(); |
| 332 auto first_deleted = std::remove_if( | 351 auto first_deleted = std::remove_if( |
| 333 list_value.begin(), list_value.end(), | 352 list_value.begin(), list_value.end(), |
| 334 [filter](const Value& v) { | 353 [filter](const Value& v) { |
| (...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 755 return ExecuteGreaterEquals(scope, op_node, left_value, right_value, err); | 774 return ExecuteGreaterEquals(scope, op_node, left_value, right_value, err); |
| 756 if (op.type() == Token::LESS_EQUAL) | 775 if (op.type() == Token::LESS_EQUAL) |
| 757 return ExecuteLessEquals(scope, op_node, left_value, right_value, err); | 776 return ExecuteLessEquals(scope, op_node, left_value, right_value, err); |
| 758 if (op.type() == Token::GREATER_THAN) | 777 if (op.type() == Token::GREATER_THAN) |
| 759 return ExecuteGreater(scope, op_node, left_value, right_value, err); | 778 return ExecuteGreater(scope, op_node, left_value, right_value, err); |
| 760 if (op.type() == Token::LESS_THAN) | 779 if (op.type() == Token::LESS_THAN) |
| 761 return ExecuteLess(scope, op_node, left_value, right_value, err); | 780 return ExecuteLess(scope, op_node, left_value, right_value, err); |
| 762 | 781 |
| 763 return Value(); | 782 return Value(); |
| 764 } | 783 } |
| OLD | NEW |