diff --git a/CHANGELOG.md b/CHANGELOG.md index eb9eddd8..a954ae69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ ## 0.7.4+2 +* **BUG FIX**: `ConstantReader.revive()` now properly returns no URL fragment + when the constant expression is resolved from a top-level or static-field. + The documentation had said otherwise, and it was impossible to tell the + difference between a constructor and a field. _Now_, fields are always in + the form of accessor = `{clazz}.{field}` or `{topLevelField}`. + * Fix file URIs on windows. ## 0.7.4+1 diff --git a/lib/src/constants/revive.dart b/lib/src/constants/revive.dart index 7d89da00..c458f639 100644 --- a/lib/src/constants/revive.dart +++ b/lib/src/constants/revive.dart @@ -22,10 +22,24 @@ Revivable reviveInstance(DartObject object, [LibraryElement origin]) { origin ??= object.type.element.library; var url = Uri.parse(urlOfElement(object.type.element)); final clazz = object?.type?.element as ClassElement; - for (final e in clazz.fields.where( - (f) => f.isPublic && f.isConst && f.computeConstantValue() == object, - )) { - return new Revivable._(source: url, accessor: e.name); + // Enums are not included in .definingCompilationUnit.types. + if (clazz.isEnum) { + for (final e in clazz.fields.where( + (f) => f.isPublic && f.isConst && f.computeConstantValue() == object)) { + return new Revivable._( + source: url.removeFragment(), + accessor: '${clazz.name}.${e.name}', + ); + } + } + for (final e in origin.definingCompilationUnit.types + .expand((t) => t.fields) + .where((f) => + f.isPublic && f.isConst && f.computeConstantValue() == object)) { + return new Revivable._( + source: url.removeFragment(), + accessor: '${clazz.name}.${e.name}', + ); } final i = (object as DartObjectImpl).getInvocation(); if (i != null && diff --git a/test/constants_test.dart b/test/constants_test.dart index 6048d0db..ea098cca 100644 --- a/test/constants_test.dart +++ b/test/constants_test.dart @@ -194,6 +194,7 @@ void main() { @MapLike() @VisibleClass.secret() @fieldOnly + @ClassWithStaticField.staticField class Example {} class Int64Like { @@ -230,8 +231,13 @@ void main() { class _FieldOnlyVisible { const _FieldOnlyVisible(); } - + const fieldOnly = const _FieldOnlyVisible(); + + class ClassWithStaticField { + static const staticField = const ClassWithStaticField._(); + const ClassWithStaticField._(); + } ''', (resolver) => resolver.findLibraryByName('test_lib')); constants = library .getType('Example') @@ -242,8 +248,8 @@ void main() { test('should decode Int64Like.ZERO', () { final int64Like0 = constants[0].revive(); - expect(int64Like0.source.toString(), endsWith('#Int64Like')); - expect(int64Like0.accessor, 'ZERO'); + expect(int64Like0.source.fragment, isEmpty); + expect(int64Like0.accessor, 'Int64Like.ZERO'); }); test('should decode Duration', () { @@ -260,8 +266,8 @@ void main() { test('should decode enums', () { final enumField1 = constants[2].revive(); - expect(enumField1.source.toString(), endsWith('#Enum')); - expect(enumField1.accessor, 'field1'); + expect(enumField1.source.fragment, isEmpty); + expect(enumField1.accessor, 'Enum.field1'); }); test('should decode forwarding factories', () { @@ -281,5 +287,11 @@ void main() { expect(fieldOnly.source.fragment, isEmpty); expect(fieldOnly.accessor, 'fieldOnly'); }); + + test('should decode static fields', () { + final fieldOnly = constants[6].revive(); + expect(fieldOnly.source.fragment, isEmpty); + expect(fieldOnly.accessor, 'ClassWithStaticField.staticField'); + }); }); }