Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.6.1

* Added `spanForElement`; returns a `SourceSpan` for an analyzer `Element`.

## 0.6.0

* **Breaking change**: `TypeChecker#annotationsOf|firstAnnotationOf` now
Expand Down
1 change: 1 addition & 0 deletions lib/source_gen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export 'src/generator.dart';
export 'src/generator_for_annotation.dart';
export 'src/library.dart' show LibraryReader;
export 'src/revive.dart' show Revivable;
export 'src/span_for_element.dart' show spanForElement;
export 'src/type_checker.dart' show TypeChecker;
41 changes: 41 additions & 0 deletions lib/src/span_for_element.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// 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.

import 'package:analyzer/dart/element/element.dart';
import 'package:source_span/source_span.dart';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing explicit dependency on source_span here...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, not here – in pubspec

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your wish is my command,


import 'utils.dart';

/// Returns a source span that spans the location where [element] is defined.
///
/// May be used to emit user-friendly warning and error messages:
/// ```dart
/// void invalidClass(ClassElement class) {
/// log.warning(spanForElement.message('Cannot implement "Secret"'));
/// }
/// ```
///
/// Not all results from the analyzer API may return source information as part
/// of the element, so [file] may need to be manually provided in those cases.
SourceSpan spanForElement(Element element, [SourceFile file]) {
final url = assetToPackageUrl(element.source.uri);
if (file == null) {
final contents = element?.source?.contents;
if (contents == null) {
return new SourceSpan(
new SourceLocation(
element.nameOffset,
sourceUrl: url,
),
new SourceLocation(
element.nameOffset + element.nameLength,
sourceUrl: url,
),
element.name,
);
}
file = new SourceFile.fromString(contents.data, url: url);
}
return file.span(element.nameOffset, element.nameOffset + element.nameLength);
}
22 changes: 20 additions & 2 deletions lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,13 @@ Uri normalizeDartUrl(Uri url) => url.pathSegments.isNotEmpty
? url.replace(pathSegments: url.pathSegments.take(1))
: url;

/// Returns a `package:` URL into a `asset:` URL.
/// Returns a `package:` URL converted to a `asset:` URL.
///
/// This makes internal comparison logic much easier, but still allows users
/// to define assets in terms of `package:`, which is something that makes more
/// sense to most.
///
/// For example this transforms `package:source_gen/source_gen.dart` into:
/// For example, this transforms `package:source_gen/source_gen.dart` into:
/// `asset:source_gen/lib/source_gen.dart`.
Uri packageToAssetUrl(Uri url) => url.scheme == 'package'
? url.replace(
Expand All @@ -122,6 +122,24 @@ Uri packageToAssetUrl(Uri url) => url.scheme == 'package'
..addAll(url.pathSegments.skip(1)))
: url;

/// Returns a `asset:` URL converted to a `package:` URL.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the asset: uri logic defined? For barback?

Might be nice to clarify this...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your wish is my command,

///
/// For example, this transformers `asset:source_gen/lib/source_gen.dart' into:
/// `package:source_gen/source_gen.dart`. Asset URLs that aren't pointing to a
/// file in the 'lib' folder are not modified.
///
/// Asset URLs come from `package:build`, as they are able to describe URLs that
/// are not describable using `package:...`, such as files in the `bin`, `tool`,
/// `web`, or even root directory of a package - `asset:some_lib/web/main.dart`.
Uri assetToPackageUrl(Uri url) => url.scheme == 'asset' &&
url.pathSegments.length >= 1 &&
url.pathSegments[1] == 'lib'
? url.replace(
scheme: 'package',
pathSegments: [url.pathSegments.first]
..addAll(url.pathSegments.skip(2)))
: url;

/// Returns all of the declarations in [unit], including [unit] as the first
/// item.
Iterable<Element> getElementsFromLibraryElement(LibraryElement unit) sync* {
Expand Down
3 changes: 2 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: source_gen
version: 0.6.0
version: 0.6.1-dev
author: Dart Team <misc@dartlang.org>
description: Automated source code generation for Dart.
homepage: https://github.com/dart-lang/source_gen
Expand All @@ -11,6 +11,7 @@ dependencies:
collection: ^1.1.2
dart_style: '>=0.1.7 <2.0.0'
path: ^1.3.2
source_span: ^1.0.0
dev_dependencies:
build_runner: ^0.3.2
build_test: ^0.6.0
Expand Down
31 changes: 31 additions & 0 deletions test/span_for_element_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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.

import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:build_test/build_test.dart';
import 'package:source_gen/source_gen.dart';
import 'package:test/test.dart';

void main() {
LibraryElement library;

setUpAll(() async {
final resolver = await resolveSource(r'''
library test_lib;
abstract class Example implements List {}
''', inputId: new AssetId('test_lib', 'lib/test_lib.dart'));
library = resolver.getLibraryByName('test_lib');
});

test('should highlight the use of "class Example"', () {
expect(
spanForElement(library.getType('Example')).message('Here it is'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's pretty cool!

''
'line 3, column 22 of package:test_lib/test_lib.dart: Here it is\n'
' abstract class Example implements List {}\n'
' ^^^^^^^');
});
}