Skip to content

Commit

Permalink
Add typeNameOf(DartType). (dart-lang/source_gen#295)
Browse files Browse the repository at this point in the history
* Add typeNameOf(DartType).

* Dartfmt.
  • Loading branch information
matanlurey authored Jan 12, 2018
1 parent 8adb3ce commit 1d90811
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 0 deletions.
4 changes: 4 additions & 0 deletions source_gen/source_gen/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## 0.7.4-dev

* Added `typeNameOf`, which is a safe way to get the name of a `DartType`,
even when the type is a `FunctionType`, which has a `null` name in newer
versions of the Dart analyzer.

* Added `LibraryReader.pathToUrl(Uri|String)`, which computes the `import` or
`export` path necessary to reach the provided URL from the current library.
Also added `pathToAsset` and `pathToElement` as convenience functions.
Expand Down
1 change: 1 addition & 0 deletions source_gen/source_gen/lib/source_gen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export 'src/generator_for_annotation.dart';
export 'src/library.dart' show AnnotatedElement, LibraryReader;
export 'src/span_for_element.dart' show spanForElement;
export 'src/type_checker.dart' show TypeChecker;
export 'src/utils.dart' show typeNameOf;
21 changes: 21 additions & 0 deletions source_gen/source_gen/lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.

import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:build/build.dart';
import 'package:path/path.dart' as p;

Expand Down Expand Up @@ -39,6 +40,26 @@ String friendlyNameForElement(Element element) {
return names.join(' ');
}

/// Returns a non-null name for the provided [type].
///
/// In newer versions of the Dart analyzer, a `typedef` does not keep the
/// existing `name`, because it is used an alias:
/// ```
/// // Used to return `VoidFunc` for name, is now `null`.
/// typedef VoidFunc = void Function();
/// ```
///
/// This function will return `'VoidFunc'`, unlike [DartType.name].
String typeNameOf(DartType type) {
if (type is FunctionType) {
final element = type.element;
if (element is GenericFunctionTypeElement) {
return element.enclosingElement.name;
}
}
return type.name;
}

/// Returns a name suitable for `part of "..."` when pointing to [element].
///
/// Returns `null` if [element] is missing identifier.
Expand Down
43 changes: 43 additions & 0 deletions source_gen/source_gen/test/utils_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// Increase timeouts on this test which resolves source code and can be slow.
@Timeout.factor(2.0)
import 'package:analyzer/dart/element/element.dart';
import 'package:build_test/build_test.dart';
import 'package:source_gen/source_gen.dart';
import 'package:test/test.dart';

void main() {
ClassElement example;

setUpAll(() async {
const source = r'''
library example;
abstract class Example {
ClassType classType();
FunctionType functionType();
}
class ClassType {}
typedef FunctionType();
''';
example = await resolveSource(
source,
(resolver) => resolver
.findLibraryByName('example')
.then((e) => e.getType('Example')));
});

test('should return the name of a class type', () {
final classType = example.methods.first.returnType;
expect(typeNameOf(classType), 'ClassType');
});

test('should return the name of a function type', () {
final functionType = example.methods.last.returnType;
expect(typeNameOf(functionType), 'FunctionType');
});
}

0 comments on commit 1d90811

Please sign in to comment.