support more types of expressions

R=sigmund@google.com

Review URL: https://codereview.chromium.org//951463004
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a7ccf90..69b7cc8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+## 0.5.1
+
+* Added support for more types of expressions in constructor annotations. More
+specifically, any const expressions that evaluate to a `String`, `int`,
+`double`, or `bool` are now allowed. The evaluated value is what will be inlined
+in the bootstrap file in this case.
+
+
 ## 0.5.0
 
 * The `InitializePluginTransformer` is gone in favor of a new
diff --git a/lib/build/initializer_plugin.dart b/lib/build/initializer_plugin.dart
index 035161e..f70e885 100644
--- a/lib/build/initializer_plugin.dart
+++ b/lib/build/initializer_plugin.dart
@@ -92,8 +92,6 @@
     var constructor = annotation.constructorName == null
         ? ''
         : '.${annotation.constructorName}';
-    // TODO(jakemac): Support more than raw values here
-    // https://github.com/dart-lang/static_init/issues/5
     var args = buildArgumentList(annotation.arguments, pluginData);
     return 'const $metaPrefix.${clazz}$constructor$args';
   }
@@ -202,14 +200,8 @@
     var logger = pluginData.logger;
     var libraryPrefixes = pluginData.libraryPrefixes;
     var buffer = new StringBuffer();
-    if (expression is StringLiteral) {
-      var value = expression.stringValue;
-      if (value == null) {
-        logger.error('Only const strings are allowed in initializer '
-            'expressions, found $expression');
-      }
-      value = value.replaceAll(r'\', r'\\').replaceAll(r"'", r"\'");
-      buffer.write("'$value'");
+    if (expression is StringLiteral && expression.stringValue != null) {
+      buffer.write(_stringValue(expression.stringValue));
     } else if (expression is BooleanLiteral ||
         expression is DoubleLiteral ||
         expression is IntegerLiteral ||
@@ -239,7 +231,7 @@
       var element = expression.bestElement;
       if (element == null || !element.isPublic) {
         logger.error('Private constants are not supported in intializer '
-            'constructors, found $element.');
+        'constructors, found $element.');
       }
       libraryPrefixes.putIfAbsent(
           element.library, () => 'i${libraryPrefixes.length}');
@@ -256,10 +248,38 @@
       } else {
         logger.error('Unsupported argument to initializer constructor.');
       }
+    } else if (expression is PropertyAccess) {
+      buffer.write(buildExpression(expression.target, pluginData));
+      buffer.write('.${expression.propertyName}');
+    } else if (expression is InstanceCreationExpression) {
+      logger.error('Unsupported expression in initializer, found $expression. '
+          'Instance creation expressions are not supported (yet). Instead, '
+          'please assign it to a const variable and use that instead.');
     } else {
-      logger.error('Only literals and identifiers are allowed for initializer '
-          'expressions, found $expression.');
+      // Try to evaluate the constant and use that.
+      var result = pluginData.resolver.evaluateConstant(
+          pluginData.initializer.targetElement.library, expression);
+      if (!result.isValid) {
+        logger.error('Invalid expression in initializer, found $expression. '
+            'And got the following errors: ${result.errors}.');
+      }
+      var value = result.value.value;
+      if (value == null) {
+        logger.error('Unsupported expression in initializer, found '
+            '$expression. Please file a bug at '
+            'https://github.com/dart-lang/initialize/issues');
+      }
+
+      if (value is String) value = _stringValue(value);
+      buffer.write(value);
     }
     return buffer.toString();
   }
+
+  // Returns an expression for a string value. Wraps it in single quotes and
+  // escapes existing single quotes and escapes.
+  _stringValue(String value) {
+    value = value.replaceAll(r'\', r'\\').replaceAll(r"'", r"\'");
+    return "'$value'";
+  }
 }
diff --git a/pubspec.yaml b/pubspec.yaml
index dea7882..59ca83e 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: initialize
-version: 0.5.0
+version: 0.5.1
 author: Polymer.dart Authors <web@dartlang.org>
 description: Generic building blocks for doing static initialization.
 homepage: https://github.com/dart-lang/initialize
diff --git a/test/transformer_test.dart b/test/transformer_test.dart
index 12e3259..e90eefc 100644
--- a/test/transformer_test.dart
+++ b/test/transformer_test.dart
@@ -117,6 +117,8 @@
     'a|web/index.dart': '''
         @DynamicInit(foo)
         @DynamicInit(Foo.foo)
+        @DynamicInit(bar.Foo.bar)
+        @DynamicInit(bar.Foo.foo)
         @DynamicInit(const [foo, Foo.foo, 'foo'])
         @DynamicInit(const {'foo': foo, 'Foo.foo': Foo.foo, 'bar': 'bar'})
         @DynamicInit('foo')
@@ -124,19 +126,36 @@
         @DynamicInit(null)
         @DynamicInit(1)
         @DynamicInit(1.1)
+        @DynamicInit('foo-\$x\${y}')
+        @DynamicInit(1 + 2)
+        @DynamicInit(1.0 + 0.2)
+        @DynamicInit(1 == 1)
         @NamedArgInit(1, name: 'Bill')
         library web_foo;
 
         import 'package:test_initializers/common.dart';
         import 'foo.dart';
+        import 'foo.dart' as bar;
+
+        const x = 'x';
+        const y = 'y';
+
+        class MyConst {
+          const MyConst;
+        }
         ''',
     'a|web/foo.dart': '''
         library foo;
 
         const String foo = 'foo';
 
+        class Bar {
+          const Bar();
+        }
+
         class Foo {
           static foo = 'Foo.foo';
+          static bar = const Bar();
         }
         ''',
     // Mock out the Initialize package plus some initializers.
@@ -154,6 +173,8 @@
           initializers.addAll([
             new InitEntry(const i1.DynamicInit(i2.foo), const LibraryIdentifier(#web_foo, null, 'index.dart')),
             new InitEntry(const i1.DynamicInit(i2.Foo.foo), const LibraryIdentifier(#web_foo, null, 'index.dart')),
+            new InitEntry(const i1.DynamicInit(i2.Foo.bar), const LibraryIdentifier(#web_foo, null, 'index.dart')),
+            new InitEntry(const i1.DynamicInit(i2.Foo.foo), const LibraryIdentifier(#web_foo, null, 'index.dart')),
             new InitEntry(const i1.DynamicInit(const [i2.foo, i2.Foo.foo, 'foo']), const LibraryIdentifier(#web_foo, null, 'index.dart')),
             new InitEntry(const i1.DynamicInit(const {'foo': i2.foo, 'Foo.foo': i2.Foo.foo, 'bar': 'bar'}), const LibraryIdentifier(#web_foo, null, 'index.dart')),
             new InitEntry(const i1.DynamicInit('foo'), const LibraryIdentifier(#web_foo, null, 'index.dart')),
@@ -161,6 +182,10 @@
             new InitEntry(const i1.DynamicInit(null), const LibraryIdentifier(#web_foo, null, 'index.dart')),
             new InitEntry(const i1.DynamicInit(1), const LibraryIdentifier(#web_foo, null, 'index.dart')),
             new InitEntry(const i1.DynamicInit(1.1), const LibraryIdentifier(#web_foo, null, 'index.dart')),
+            new InitEntry(const i1.DynamicInit('foo-xy'), const LibraryIdentifier(#web_foo, null, 'index.dart')),
+            new InitEntry(const i1.DynamicInit(3), const LibraryIdentifier(#web_foo, null, 'index.dart')),
+            new InitEntry(const i1.DynamicInit(1.2), const LibraryIdentifier(#web_foo, null, 'index.dart')),
+            new InitEntry(const i1.DynamicInit(true), const LibraryIdentifier(#web_foo, null, 'index.dart')),
             new InitEntry(const i1.NamedArgInit(1, name: 'Bill'), const LibraryIdentifier(#web_foo, null, 'index.dart')),
           ]);