diff --git a/runtime/lib/string.cc b/runtime/lib/string.cc index 486ff33a687..50636fc88f0 100644 --- a/runtime/lib/string.cc +++ b/runtime/lib/string.cc @@ -117,6 +117,27 @@ DEFINE_NATIVE_ENTRY(String_concat, 2) { } +// TODO(hausner): Remove obsolete String_plus. +DECLARE_FLAG(bool, allow_string_plus); +DEFINE_NATIVE_ENTRY(String_plus, 2) { + const String& receiver = String::CheckedHandle(arguments->At(0)); + GET_NATIVE_ARGUMENT(String, b, arguments->At(1)); + if (!FLAG_allow_string_plus) { + // Throw a noSuchMethod exception if operator + is not supported. + const String& func_name = String::Handle(String::New("+")); + const Array& func_args = Array::Handle(Array::New(1)); + func_args.SetAt(0, b); + GrowableArray dart_arguments(3); + dart_arguments.Add(&receiver); + dart_arguments.Add(&func_name); + dart_arguments.Add(&func_args); + Exceptions::ThrowByType(Exceptions::kNoSuchMethod, dart_arguments); + } + const String& result = String::Handle(String::Concat(receiver, b)); + arguments->SetReturn(result); +} + + DEFINE_NATIVE_ENTRY(String_toLowerCase, 1) { const String& receiver = String::CheckedHandle(arguments->At(0)); ASSERT(!receiver.IsNull()); diff --git a/runtime/lib/string.dart b/runtime/lib/string.dart index 7bcbda14023..c2b5579954c 100644 --- a/runtime/lib/string.dart +++ b/runtime/lib/string.dart @@ -232,12 +232,18 @@ class StringBase { return buffer.add(this.substring(startIndex)).toString(); } + /** + * TODO(hausner): remove support for operator + and native method plus(). + */ + String plus(String other) native "String_plus"; + /** * Convert argument obj to string and concat it with this string. * Returns concatenated string. + * TODO(hausner): remove support for +. */ String operator +(Object obj) { - return this.concat(obj.toString()); + return this.plus(obj.toString()); } /** diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h index 040a2272be6..631c5d432e2 100644 --- a/runtime/vm/bootstrap_natives.h +++ b/runtime/vm/bootstrap_natives.h @@ -76,6 +76,7 @@ namespace dart { V(String_charAt, 2) \ V(String_charCodeAt, 2) \ V(String_concat, 2) \ + V(String_plus, 2) \ V(String_toLowerCase, 1) \ V(String_toUpperCase, 1) \ V(Strings_concatAll, 1) \ diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc index d69ba1e3446..cb35ec3e632 100644 --- a/runtime/vm/parser.cc +++ b/runtime/vm/parser.cc @@ -26,6 +26,7 @@ DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks."); DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations."); DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors."); DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings."); +DEFINE_FLAG(bool, allow_string_plus, true, "Allow + operator on strings."); static void CheckedModeHandler(bool value) { FLAG_enable_asserts = value; @@ -5702,8 +5703,12 @@ AstNode* Parser::ParseBinaryExpr(int min_preced) { if (left_operand->IsLiteralNode()) { LiteralNode* lit = left_operand->AsLiteralNode(); if (lit->literal().IsString()) { - str_concat = new StringConcatNode(lit->token_index()); - str_concat->AddExpr(lit); + if (FLAG_allow_string_plus) { + str_concat = new StringConcatNode(lit->token_index()); + str_concat->AddExpr(lit); + } else { + ErrorMsg(op_pos, "operator + on strings no longer allowed"); + } } } else if (left_operand->IsStringConcatNode()) { str_concat = left_operand->AsStringConcatNode();