fix(dart/transformer): Correctly handle const object annotations
Previously, annotations which were const objects (as opposed to const instance creation expressions) were incorrectly output as instance creation expressions. Before: ``` const override() // A const instance creation expression ``` After ``` override // A const instance ``` Closes #4481
This commit is contained in:
@@ -16,49 +16,65 @@ void allTests() {
|
||||
|
||||
it('should generate a setter for an `inputs` property in an annotation.',
|
||||
() async {
|
||||
var inputPath = 'bind_generator/basic_bind_files/bar.ng_deps.dart';
|
||||
var expected = formatter.format(
|
||||
readFile('bind_generator/basic_bind_files/expected/bar.ng_deps.dart'));
|
||||
var inputPath = 'basic_bind_files/bar.ng_deps.dart';
|
||||
var expected = _readFile('basic_bind_files/expected/bar.ng_deps.dart');
|
||||
|
||||
var output = formatter.format(
|
||||
await createNgSettersAndGetters(reader, new AssetId('a', inputPath)));
|
||||
var output = formatter
|
||||
.format(await createNgSettersAndGetters(reader, _assetId(inputPath)));
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
|
||||
it(
|
||||
'should generate a single setter when multiple annotations bind to the '
|
||||
'same `inputs` property.', () async {
|
||||
var inputPath =
|
||||
'bind_generator/duplicate_bind_name_files/soup.ng_deps.dart';
|
||||
var expected = formatter.format(readFile(
|
||||
'bind_generator/duplicate_bind_name_files/expected/soup.ng_deps.dart'));
|
||||
var inputPath = 'duplicate_bind_name_files/soup.ng_deps.dart';
|
||||
var expected =
|
||||
_readFile('duplicate_bind_name_files/expected/soup.ng_deps.dart');
|
||||
|
||||
var output = formatter.format(
|
||||
await createNgSettersAndGetters(reader, new AssetId('a', inputPath)));
|
||||
var output = formatter
|
||||
.format(await createNgSettersAndGetters(reader, _assetId(inputPath)));
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should generate setters for queries defined in the class annotation.',
|
||||
() async {
|
||||
var inputPath =
|
||||
'bind_generator/queries_class_annotation_files/bar.ng_deps.dart';
|
||||
var expected = formatter.format(readFile(
|
||||
'bind_generator/queries_class_annotation_files/expected/bar.ng_deps.dart'));
|
||||
var inputPath = 'queries_class_annotation_files/bar.ng_deps.dart';
|
||||
var expected =
|
||||
_readFile('queries_class_annotation_files/expected/bar.ng_deps.dart');
|
||||
|
||||
var output = formatter.format(
|
||||
await createNgSettersAndGetters(reader, new AssetId('a', inputPath)));
|
||||
var output = formatter
|
||||
.format(await createNgSettersAndGetters(reader, _assetId(inputPath)));
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should generate setters for queries defined via prop annotations.',
|
||||
() async {
|
||||
var inputPath =
|
||||
'bind_generator/queries_prop_annotations_files/bar.ng_deps.dart';
|
||||
var expected = formatter.format(readFile(
|
||||
'bind_generator/queries_prop_annotations_files/expected/bar.ng_deps.dart'));
|
||||
var inputPath = 'queries_prop_annotations_files/bar.ng_deps.dart';
|
||||
var expected =
|
||||
_readFile('queries_prop_annotations_files/expected/bar.ng_deps.dart');
|
||||
|
||||
var output = formatter.format(
|
||||
await createNgSettersAndGetters(reader, new AssetId('a', inputPath)));
|
||||
var output = formatter
|
||||
.format(await createNgSettersAndGetters(reader, _assetId(inputPath)));
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should gracefully handle const objects as prop annotations.', () async {
|
||||
var inputPath = 'queries_override_annotation_files/bar.ng_deps.dart';
|
||||
var expected = formatter.format(_readFile(
|
||||
'queries_override_annotation_files/expected/bar.ng_deps.dart'));
|
||||
|
||||
var output = formatter
|
||||
.format(await createNgSettersAndGetters(reader, _assetId(inputPath)));
|
||||
expect(output).toEqual(expected);
|
||||
});
|
||||
}
|
||||
|
||||
AssetId _assetId(String path) => new AssetId('a', 'bind_generator/$path');
|
||||
|
||||
String _readFile(String path) {
|
||||
var code = readFile('bind_generator/$path');
|
||||
if (path.endsWith('.dart')) {
|
||||
code = formatter.format(code);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
library bar.ng_deps.dart;
|
||||
|
||||
import 'bar.dart';
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector(reflector) {
|
||||
if (_visited) return;
|
||||
_visited = true;
|
||||
reflector
|
||||
..registerType(
|
||||
ToolTip,
|
||||
new ReflectionInfo(
|
||||
const [const Directive(selector: '[tool-tip]')],
|
||||
const [],
|
||||
() => new ToolTip(),
|
||||
null,
|
||||
const {
|
||||
'queryField': const [override]
|
||||
}));
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
library bar.ng_deps.dart;
|
||||
|
||||
import 'bar.dart';
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
|
||||
var _visited = false;
|
||||
void initReflector(reflector) {
|
||||
if (_visited) return;
|
||||
_visited = true;
|
||||
reflector
|
||||
..registerType(
|
||||
ToolTip,
|
||||
new ReflectionInfo(
|
||||
const [const Directive(selector: '[tool-tip]')],
|
||||
const [],
|
||||
() => new ToolTip(),
|
||||
null,
|
||||
const {
|
||||
'queryField': const [override]
|
||||
}));
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import 'package:angular2/src/core/linker/interfaces.dart' show LifecycleHooks;
|
||||
import 'package:angular2/src/core/dom/html_adapter.dart';
|
||||
import 'package:angular2/src/transform/directive_processor/rewriter.dart';
|
||||
import 'package:angular2/src/transform/common/annotation_matcher.dart';
|
||||
import 'package:angular2/src/transform/common/code/ng_deps_code.dart';
|
||||
import 'package:angular2/src/transform/common/asset_reader.dart';
|
||||
import 'package:angular2/src/transform/common/logging.dart' as log;
|
||||
import 'package:angular2/src/transform/common/model/reflection_info_model.pb.dart';
|
||||
@@ -210,9 +211,32 @@ void allTests() {
|
||||
expect(model.reflectables.first.propertyMetadata.isNotEmpty).toBeTrue();
|
||||
expect(model.reflectables.first.propertyMetadata.first.name)
|
||||
.toEqual('getVal');
|
||||
expect(model.reflectables.first.propertyMetadata.first.annotations
|
||||
.firstWhere((a) => a.name == 'GetDecorator', orElse: () => null))
|
||||
.toBeNotNull();
|
||||
|
||||
var getDecoratorAnnotation = model
|
||||
.reflectables.first.propertyMetadata.first.annotations
|
||||
.firstWhere((a) => a.name == 'GetDecorator', orElse: () => null);
|
||||
expect(getDecoratorAnnotation).toBeNotNull();
|
||||
expect(getDecoratorAnnotation.isConstObject).toBeFalse();
|
||||
});
|
||||
|
||||
it('should gracefully handle const instances of annotations', () async {
|
||||
// Regression test for i/4481
|
||||
var model = await _testCreateModel('prop_metadata_files/override.dart');
|
||||
|
||||
expect(model.reflectables.first.propertyMetadata).toBeNotNull();
|
||||
expect(model.reflectables.first.propertyMetadata.isNotEmpty).toBeTrue();
|
||||
expect(model.reflectables.first.propertyMetadata.first.name)
|
||||
.toEqual('getVal');
|
||||
var overrideAnnotation = model
|
||||
.reflectables.first.propertyMetadata.first.annotations
|
||||
.firstWhere((a) => a.name == 'override', orElse: () => null);
|
||||
|
||||
expect(overrideAnnotation).toBeNotNull();
|
||||
expect(overrideAnnotation.isConstObject).toBeTrue();
|
||||
|
||||
var buf = new StringBuffer();
|
||||
new NgDepsWriter(buf).writeAnnotationModel(overrideAnnotation);
|
||||
expect(buf.toString()).toEqual('override');
|
||||
});
|
||||
|
||||
it('should be recorded on setters', () async {
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
library override;
|
||||
|
||||
import 'package:angular2/src/core/metadata.dart';
|
||||
|
||||
@Component(selector: '[getters]')
|
||||
@View(template: '')
|
||||
class FieldComponent implements ValGetter {
|
||||
@override
|
||||
String get getVal => 'a';
|
||||
}
|
||||
|
||||
abstract class ValGetter {
|
||||
String get getVal;
|
||||
}
|
||||
Reference in New Issue
Block a user