Automated g4 rollback of changelist 130164706.

*** Reason for rollback ***

Failing test in //transconsole/api/handlers/test/dart:dart_generate_localized_files_test

*** Original change description ***

Intl messages with no parameters and no name use contents for the name.

This is the first part of getting rid of the Intl transformer. With this, it's only necessary to provide explicit names for messages with arguments. Zero-argument messages are 75+% of the total.

Many of the changes relate to characters not valid in Dart identifiers in the names, and in generating method names for them. It also has a small amount of restructuring to make room for a possible alternate syntax for messages wit...

***

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=130188264
diff --git a/bin/generate_from_arb.dart b/bin/generate_from_arb.dart
index 13d3680..fd46857 100644
--- a/bin/generate_from_arb.dart
+++ b/bin/generate_from_arb.dart
@@ -66,18 +66,13 @@
     exit(0);
   }
 
-  // TODO(alanknight): There is a possible regression here. If a project is
-  // using the transformer and expecting it to provide names for messages with
-  // parameters, we may report those names as missing. We now have two distinct
-  // mechanisms for providing names: the transformer and just using the message
-  // text if there are no parameters. Previously this was always acting as if
-  // the transformer was in use, but that breaks the case of using the message
-  // text. The intent is to deprecate the transformer, but if this is an issue
-  // for real projects we could provide a command-line flag to indicate which
-  // sort of automated name we're using.
+  // We're re-parsing the original files to find the corresponding messages,
+  // so if there are warnings extracting the messages, suppress them, and
+  // always pretend the transformer was in use so we don't fail for missing
+  // names/args.
   extraction.suppressWarnings = true;
   var allMessages =
-      dartFiles.map((each) => extraction.parseFile(new File(each), false));
+      dartFiles.map((each) => extraction.parseFile(new File(each), true));
 
   messages = new Map();
   for (var eachMap in allMessages) {
diff --git a/lib/extract_messages.dart b/lib/extract_messages.dart
index e9c13b8..33a234e 100644
--- a/lib/extract_messages.dart
+++ b/lib/extract_messages.dart
@@ -241,14 +241,17 @@
   /// by calling [setAttribute]. This is the common parts between
   /// [messageFromIntlMessageCall] and [messageFromDirectPluralOrGenderCall].
   MainMessage _messageFromNode(
-      MethodInvocation node,
-      MainMessage extract(MainMessage message, List<AstNode> arguments),
-      void setAttribute(
-          MainMessage message, String fieldName, Object fieldValue)) {
+      MethodInvocation node, Function extract, Function setAttribute) {
     var message = new MainMessage();
     message.sourcePosition = node.offset;
     message.endPosition = node.end;
-
+    if (generateNameAndArgs) {
+      // Always try for class_method if this is a class method and transforming.
+      // It will be overwritten below if the message specifies it explicitly.
+      message.name = Message.classPlusMethodName(node, name) ?? name;
+    } else {
+      message.name = name;
+    }
     message.arguments =
         parameters.parameters.map((x) => x.identifier.name).toList();
     var arguments = node.argumentList.arguments;
@@ -266,49 +269,27 @@
           : basicValue;
       setAttribute(message, name, value);
     }
-    if (message.name == "") {
-      if (generateNameAndArgs) {
-        // Always try for class_method if this is a class method and
-        // transforming.
-        message.name = Message.classPlusMethodName(node, name) ?? name;
-      } else if (arguments.first is SimpleStringLiteral ||
-          arguments.first is AdjacentStrings) {
-        // If there's no name, and the message text is a single string, use it
-        // as the name
-        message.name = (arguments.first as StringLiteral).stringValue;
-      }
-    }
     return message;
   }
 
-  /// Find the message pieces from a Dart interpolated string.
-  List _extractFromIntlCallWithInterpolation(
-      MainMessage message, List<AstNode> arguments) {
-    var interpolation = new InterpolationVisitor(message, extraction);
-    arguments.first.accept(interpolation);
-    if (interpolation.pieces.any((x) => x is Plural || x is Gender) &&
-        !extraction.allowEmbeddedPluralsAndGenders) {
-      if (interpolation.pieces.any((x) => x is String && x.isNotEmpty)) {
-        throw new IntlMessageExtractionException(
-            "Plural and gender expressions must be at the top level, "
-            "they cannot be embedded in larger string literals.\n");
-      }
-    }
-    return interpolation.pieces;
-  }
-
   /// Create a MainMessage from [node] using the name and
   /// parameters of the last function/method declaration we encountered
   /// and the parameters to the Intl.message call.
   MainMessage messageFromIntlMessageCall(MethodInvocation node) {
-    MainMessage extractFromIntlCall(
-        MainMessage message, List<AstNode> arguments) {
+    MainMessage extractFromIntlCall(MainMessage message, List arguments) {
       try {
-        // The pieces of the message, either literal strings, or integers
-        // representing the index of the argument to be substituted.
-        List extracted;
-        extracted = _extractFromIntlCallWithInterpolation(message, arguments);
-        message.addPieces(extracted);
+        var interpolation = new InterpolationVisitor(message, extraction);
+        arguments.first.accept(interpolation);
+        if (interpolation.pieces.any((x) => x is Plural || x is Gender) &&
+            !extraction.allowEmbeddedPluralsAndGenders) {
+          if (interpolation.pieces.any((x) => x is String && x.isNotEmpty)) {
+            throw new IntlMessageExtractionException(
+                "Plural and gender expressions must be at the top level, "
+                "they cannot be embedded in larger string literals.\n"
+                "Error at $node");
+          }
+        }
+        message.messagePieces.addAll(interpolation.pieces as List<Message>);
       } on IntlMessageExtractionException catch (e) {
         message = null;
         var err = new StringBuffer()
@@ -318,7 +299,7 @@
         extraction.onMessage(errString);
         extraction.warnings.add(errString);
       }
-      return message;
+      return message; // Because we may have set it to null on an error.
     }
 
     void setValue(MainMessage message, String fieldName, Object fieldValue) {
@@ -489,8 +470,7 @@
         break;
       default:
         throw new IntlMessageExtractionException(
-            "Invalid plural/gender/select message ${node.methodName.name} "
-            "in $node");
+            "Invalid plural/gender/select message");
     }
     message.parent = parent;
 
diff --git a/lib/generate_localized.dart b/lib/generate_localized.dart
index f443ad7..f6f3c44 100644
--- a/lib/generate_localized.dart
+++ b/lib/generate_localized.dart
@@ -72,8 +72,7 @@
       for (var original in messagesThatNeedMethods) {
         result
           ..write("  ")
-          ..write(
-              original.toCodeForLocale(locale, _methodNameFor(original.name)))
+          ..write(original.toCodeForLocale(locale))
           ..write("\n\n");
       }
     }
@@ -86,12 +85,11 @@
     var entries = usableTranslations
         .expand((translation) => translation.originalMessages)
         .map((original) =>
-            '    "${original.escapeAndValidateString(original.name)}" '
-            ': ${_mapReference(original, locale)}');
+            '    "${original.name}" : ${_mapReference(original, locale)}');
     result..write(entries.join(",\n"))..write("\n  };\n}\n");
 
-    // To preserve compatibility, we don't use the canonical version of the
-    // locale in the file name.
+    // To preserve compatibility, we don't use the canonical version of the locale
+    // in the file name.
     var filename = path.join(
         targetDir, "${generatedFilePrefix}messages_$basicLocale.dart");
     new File(filename).writeAsStringSync(result.toString());
@@ -256,19 +254,6 @@
     return 'MessageLookupByLibrary.simpleMessage("'
         '${original.translations[locale]}")';
   } else {
-    return _methodNameFor(original.name);
+    return original.name;
   }
 }
-
-/// Generated method counter for use in [_methodNameFor].
-int _methodNameCounter = 0;
-
-/// A map from Intl message names to the generated method names
-/// for their translated versions.
-Map<String, String> _internalMethodNames = {};
-
-/// Generate a Dart method name of the form "m<number>".
-String _methodNameFor(String name) {
-  return _internalMethodNames.putIfAbsent(
-      name, () => "m${_methodNameCounter++}");
-}
diff --git a/lib/message_lookup_by_library.dart b/lib/message_lookup_by_library.dart
index a3d89ac..bf8adf3 100644
--- a/lib/message_lookup_by_library.dart
+++ b/lib/message_lookup_by_library.dart
@@ -38,22 +38,15 @@
   /// If nothing is found, return [message_str]. The [desc] and [examples]
   /// parameters are ignored
   String lookupMessage(
-      String message_str, String locale, String name, List args,
-      {MessageIfAbsent ifAbsent: _useOriginal}) {
+      String message_str, String locale, String name, List args) {
     // If passed null, use the default.
     var knownLocale = locale ?? Intl.getCurrentLocale();
     var messages = (knownLocale == _lastLocale)
         ? _lastLookup
         : _lookupMessageCatalog(knownLocale);
-    // If we didn't find any messages for this locale, use the original string,
-    // faking interpolations if necessary.
-    if (messages == null) {
-      return ifAbsent(message_str, args);
-    }
-    // If the name is blank, use the message as a key
-    return messages.lookupMessage(
-        message_str, locale, name ?? message_str, args,
-        ifAbsent: ifAbsent);
+    // If we didn't find any messages for this locale, use the original string.
+    if (messages == null) return message_str;
+    return messages.lookupMessage(message_str, locale, name, args);
   }
 
   /// Find the right message lookup for [locale].
@@ -84,9 +77,6 @@
   }
 }
 
-/// The default ifAbsent method, just returns the message string.
-String _useOriginal(String message_str, List args) => message_str;
-
 /// This provides an abstract class for messages looked up in generated code.
 /// Each locale will have a separate subclass of this class with its set of
 /// messages. See generate_localized.dart.
@@ -112,17 +102,10 @@
   /// will be extracted automatically but for the time being it must be passed
   /// explicitly in the [name] and [args] arguments.
   String lookupMessage(
-      String message_str, String locale, String name, List args,
-      {MessageIfAbsent ifAbsent}) {
-    var notFound = false;
-    if (name == null) notFound = true;
+      String message_str, String locale, String name, List args) {
+    if (name == null) return message_str;
     var function = this[name];
-    notFound = notFound || (function == null);
-    if (notFound) {
-      return ifAbsent == null ? message_str : ifAbsent(message_str, args);
-    } else {
-      return Function.apply(function, args);
-    }
+    return function == null ? message_str : Function.apply(function, args);
   }
 
   /// Return our message with the given name
diff --git a/lib/src/intl_helpers.dart b/lib/src/intl_helpers.dart
index 5556b7a..2362277 100644
--- a/lib/src/intl_helpers.dart
+++ b/lib/src/intl_helpers.dart
@@ -10,9 +10,6 @@
 import 'dart:async';
 import 'package:intl/intl.dart';
 
-/// Type for the callback action when a message translation is not found.
-typedef MessageIfAbsent(String message_str, List args);
-
 /// This is used as a marker for a locale data map that hasn't been initialized,
 /// and will throw an exception on any usage that isn't the fallback
 /// patterns/symbols provided.
@@ -25,8 +22,7 @@
       (key == 'en_US') ? fallbackData : _throwException();
 
   String lookupMessage(
-          String message_str, String locale, String name, List args,
-          {MessageIfAbsent ifAbsent}) =>
+          String message_str, String locale, String name, List args) =>
       message_str;
 
   /// Given an initial locale or null, returns the locale that will be used
@@ -47,8 +43,7 @@
 
 abstract class MessageLookup {
   String lookupMessage(
-      String message_str, String locale, String name, List args,
-      {MessageIfAbsent ifAbsent});
+      String message_str, String locale, String name, List args);
   void addLocale(String localeName, Function findLocale);
 }
 
diff --git a/lib/src/intl_message.dart b/lib/src/intl_message.dart
index b242b15..fea00fa 100644
--- a/lib/src/intl_message.dart
+++ b/lib/src/intl_message.dart
@@ -82,26 +82,19 @@
       return "The 'args' argument for Intl.message must be specified";
     }
 
-    bool useMessageAsName = false;
     var messageName = arguments.firstWhere(
         (eachArg) =>
             eachArg is NamedExpression && eachArg.name.label.name == 'name',
         orElse: () => null);
-    messageName = messageName?.expression;
-    //TODO(alanknight): If we generalize this to messages with parameters
-    // this check will need to change.
-    if (!nameAndArgsGenerated && messageName == null && !hasParameters) {
-      messageName = arguments[0];
-      useMessageAsName = true;
+    if (!nameAndArgsGenerated && messageName == null) {
+      return "The 'name' argument for Intl.message must be specified";
     }
 
-    var givenName = messageName == null ? null : _evaluateAsString(messageName);
+    var givenName =
+        messageName == null ? null : _evaluateAsString(messageName.expression);
     if (messageName != null && givenName == null) {
       return "The 'name' argument for Intl.message must be a string literal";
     }
-    if (useMessageAsName) {
-      outerName = givenName;
-    }
     var hasOuterName = outerName != null;
     var simpleMatch = outerName == givenName || givenName == null;
 
@@ -113,8 +106,7 @@
           "was '$givenName' but must be '$outerName'  or '$classPlusMethod')";
     }
 
-    var simpleArguments = arguments.where((each) =>
-        each is NamedExpression &&
+    var simpleArguments = arguments.where((each) => each is NamedExpression &&
         ["desc", "name"].contains(each.name.label.name));
     var values = simpleArguments.map((each) => each.expression).toList();
     for (var arg in values) {
@@ -179,7 +171,7 @@
       "\t": r"\t",
       "\v": r"\v",
       "'": r"\'",
-      r"$": r"\$"
+      r"$" : r"\$"
     };
 
     String _escape(String s) => escapes[s] ?? s;
@@ -324,7 +316,7 @@
         nameAndArgsGenerated: nameAndArgsGenerated);
   }
 
-  void addPieces(List<Object> messages) {
+  void addPieces(List<Message> messages) {
     for (var each in messages) {
       messagePieces.add(Message.from(each, this));
     }
@@ -350,7 +342,7 @@
   String id;
 
   /// The arguments list from the Intl.message call.
-  List<String> arguments;
+  List arguments;
 
   /// The locale argument from the Intl.message call
   String locale;
@@ -388,7 +380,7 @@
 
   /// Generate code for this message, expecting it to be part of a map
   /// keyed by name with values the function that calls Intl.message.
-  String toCodeForLocale(String locale, String name) {
+  String toCodeForLocale(String locale) {
     var out = new StringBuffer()
       ..write('static $name(')
       ..write(arguments.join(", "))
diff --git a/test/message_extraction/make_hardcoded_translation.dart b/test/message_extraction/make_hardcoded_translation.dart
index 0c3af44..ff9d7d2 100644
--- a/test/message_extraction/make_hardcoded_translation.dart
+++ b/test/message_extraction/make_hardcoded_translation.dart
@@ -16,12 +16,11 @@
 /// A list of the French translations that we will produce.
 var french = {
   "types": r"{a}, {b}, {c}",
-  "This string extends across multiple lines.":
-      "Cette message prend plusiers lignes.",
+  "multiLine": "Cette message prend plusiers lignes.",
   "message2": r"Un autre message avec un seul paramètre {x}",
   "alwaysTranslated": "Cette chaîne est toujours traduit",
   "message1": "Il s'agit d'un message",
-  "\"So-called\"": "\"Soi-disant\"",
+  "leadingQuotes": "\"Soi-disant\"",
   "trickyInterpolation": r"L'interpolation est délicate "
       r"quand elle se termine une phrase comme {s}.",
   "message3": "Caractères qui doivent être échapper, par exemple barres \\ "
@@ -33,8 +32,7 @@
   "staticMessage": "Cela vient d'une méthode statique",
   "notAlwaysTranslated": "Ce manque certaines traductions",
   "thisNameIsNotInTheOriginal": "Could this lead to something malicious?",
-  "Ancient Greek hangman characters: 𐅆𐅇.":
-      "Anciens caractères grecs jeux du pendu: 𐅆𐅇.",
+  "originalNotInBMP": "Anciens caractères grecs jeux du pendu: 𐅆𐅇.",
   "escapable": "Escapes: \n\r\f\b\t\v.",
   "sameContentsDifferentName": "Bonjour tout le monde",
   "differentNameSameContents": "Bonjour tout le monde",
@@ -73,20 +71,18 @@
       "=1{{amount} dollar Canadien}"
       "other{{amount} dollars Canadiens}}}"
       "other{N'importe quoi}"
-      "}}",
-  "literalDollar": "Cinq sous est US\$0.05",
-  r"'<>{}= +-_$()&^%$#@!~`'": r"interessant (fr): '<>{}= +-_$()&^%$#@!~`'"
+  "}}",
+  "literalDollar": "Cinq sous est US\$0.05"
 };
 
 /// A list of the German translations that we will produce.
 var german = {
   "types": r"{a}, {b}, {c}",
-  "This string extends across multiple lines.":
-      "Dieser String erstreckt sich über mehrere Zeilen erstrecken.",
+  "multiLine": "Dieser String erstreckt sich über mehrere Zeilen erstrecken.",
   "message2": r"Eine weitere Meldung mit dem Parameter {x}",
   "alwaysTranslated": "Diese Zeichenkette wird immer übersetzt",
   "message1": "Dies ist eine Nachricht",
-  "\"So-called\"": "\"Sogenannt\"",
+  "leadingQuotes": "\"Sogenannt\"",
   "trickyInterpolation": r"Interpolation ist schwierig, wenn es einen Satz "
       "wie dieser endet {s}.",
   "message3": "Zeichen, die Flucht benötigen, zB Schrägstriche \\ Dollar "
@@ -96,8 +92,7 @@
   "nonLambda": "Diese Methode ist nicht eine Lambda",
   "staticMessage": "Dies ergibt sich aus einer statischen Methode",
   "thisNameIsNotInTheOriginal": "Could this lead to something malicious?",
-  "Ancient Greek hangman characters: 𐅆𐅇.":
-      "Antike griechische Galgenmännchen Zeichen: 𐅆𐅇",
+  "originalNotInBMP": "Antike griechische Galgenmännchen Zeichen: 𐅆𐅇",
   "escapable": "Escapes: \n\r\f\b\t\v.",
   "sameContentsDifferentName": "Hallo Welt",
   "differentNameSameContents": "Hallo Welt",
@@ -137,8 +132,7 @@
       "other{{amount} Kanadischen dollar}}}"
       "other{whatever}"
       "}",
-  "literalDollar": "Fünf Cent US \$ 0.05",
-  r"'<>{}= +-_$()&^%$#@!~`'": r"interessant (de): '<>{}= +-_$()&^%$#@!~`'"
+  "literalDollar": "Fünf Cent US \$ 0.05"
 };
 
 /// The output directory for translated files.
diff --git a/test/message_extraction/sample_with_messages.dart b/test/message_extraction/sample_with_messages.dart
index c22380f..590daea 100644
--- a/test/message_extraction/sample_with_messages.dart
+++ b/test/message_extraction/sample_with_messages.dart
@@ -25,15 +25,14 @@
 
 // A string with multiple adjacent strings concatenated together, verify
 // that the parser handles this properly.
-multiLine() => Intl.message("This "
+multiLine() => Intl.message(
+    "This "
     "string "
     "extends "
     "across "
     "multiple "
-    "lines.");
-
-get interestingCharactersNoName =>
-    Intl.message("'<>{}= +-_\$()&^%\$#@!~`'", desc: "interesting characters");
+    "lines.",
+    name: "multiLine");
 
 // Have types on the enclosing function's arguments.
 types(int a, String b, List c) =>
@@ -50,10 +49,11 @@
     Intl.message("Interpolation is tricky when it ends a sentence like ${s}.",
         name: 'trickyInterpolation', args: [s]);
 
-get leadingQuotes => Intl.message("\"So-called\"");
+get leadingQuotes => Intl.message("\"So-called\"", name: 'leadingQuotes');
 
 // A message with characters not in the basic multilingual plane.
-originalNotInBMP() => Intl.message("Ancient Greek hangman characters: 𐅆𐅇.");
+originalNotInBMP() => Intl.message("Ancient Greek hangman characters: 𐅆𐅇.",
+    name: "originalNotInBMP");
 
 // A string for which we don't provide all translations.
 notAlwaysTranslated() => Intl.message("This is missing some translations",
@@ -232,7 +232,6 @@
     printOut(rentAsVerb());
     printOut(rentToBePaid());
     printOut(literalDollar());
-    printOut(interestingCharactersNoName);
   });
 }
 
diff --git a/test/message_extraction/verify_messages.dart b/test/message_extraction/verify_messages.dart
index b68abcd..f9bacc1 100644
--- a/test/message_extraction/verify_messages.dart
+++ b/test/message_extraction/verify_messages.dart
@@ -6,7 +6,6 @@
 verifyResult(ignored) {
   test("Verify message translation output", actuallyVerifyResult);
 }
-
 actuallyVerifyResult() {
   var lineIterator;
   verify(String s) {
@@ -75,7 +74,6 @@
   verify('rent');
   verify('rent');
   verify('Five cents is US\$0.05');
-  verify(r"'<>{}= +-_$()&^%$#@!~`'");
 
   var fr_lines =
       expanded.skip(1).skipWhile((line) => !line.contains('----')).toList();
@@ -142,7 +140,6 @@
   verify('loyer');
   // Using a non-French format for the currency to test interpolation.
   verify('Cinq sous est US\$0.05');
-  verify(r"interessant (fr): '<>{}= +-_$()&^%$#@!~`'");
 
   var de_lines =
       fr_lines.skip(1).skipWhile((line) => !line.contains('----')).toList();
@@ -209,5 +206,4 @@
   verify('mieten');
   verify('Miete');
   verify('Fünf Cent US \$ 0.05');
-  verify(r"interessant (de): '<>{}= +-_$()&^%$#@!~`'");
 }