Skip to content

Commit

Permalink
Nicer failures when an annotation is not resolvable (dart-lang/source…
Browse files Browse the repository at this point in the history
…_gen#201)

* Add annotationsOfExact.

* Add type checks.

* Update CHANGELOG.
  • Loading branch information
matanlurey authored Jul 6, 2017
1 parent 0052d4d commit 97762fb
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 3 deletions.
4 changes: 4 additions & 0 deletions source_gen/source_gen/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
result we've added `#annotationsOfExact|firstAnnotationOfExact` which has the
old behavior for precise checks.

* `TypeChecker#annotations...`-methods now throw a `StateError` if one or more
annotations on an element are not resolvable. This is usually a sign of a
mispelling, missing import, or missing dependency.

## 0.5.10+1

* Update minimum `analyzer` package to `0.29.10`.
Expand Down
17 changes: 14 additions & 3 deletions source_gen/source_gen/lib/src/type_checker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,27 @@ abstract class TypeChecker {
return results.isEmpty ? null : results.first;
}

DartObject _checkedConstantValue(ElementAnnotation annotation) {
final result = annotation.computeConstantValue();
if (result == null) {
throw new StateError(
'Could not resolve $annotation. An import or dependency may be '
'missing or invalid.');
}
return result;
}

/// Returns annotating constants on [element] assignable to this type.
Iterable<DartObject> annotationsOf(Element element) => element.metadata
.map((a) => a.computeConstantValue())
.map(_checkedConstantValue)
.where((a) => isAssignableFromType(a.type));

/// Returns annotating constants on [element] of exactly this type.
Iterable<DartObject> annotationsOfExact(Element element) => element.metadata
.map((a) => a.computeConstantValue())
.where((a) => isExactlyType(a.type));
.map(_checkedConstantValue)
.where((a) => a?.type != null && isAssignableFromType(a.type));

/// Returns `true` if the type of [element] can be assigned to this type.
/// Returns `true` if the type of [element] can be assigned to this type.
bool isAssignableFrom(Element element) =>
isExactly(element) || _getAllSupertypes(element).any(isExactlyType);
Expand Down
15 changes: 15 additions & 0 deletions source_gen/source_gen/test/type_checker_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,19 @@ void main() {
checkGeneratorForAnnotation: () => const TypeChecker.fromUrl(
'package:source_gen/src/generator_for_annotation.dart#GeneratorForAnnotation'));
});

test('should gracefully when something is not resolvable', () async {
final resolver = await resolveSource(r'''
library _test;
@depracated // Intentionally mispelled.
class X {}
''');
final lib = resolver.getLibraryByName('_test');
final classX = lib.getType('X');
final $deprecated = const TypeChecker.fromRuntime(Deprecated);

expect(() => $deprecated.annotationsOf(classX), throwsStateError,
reason: 'deprecated was spelled wrong; no annotation can be resolved');
});
}

0 comments on commit 97762fb

Please sign in to comment.