Skip to content

Commit c6fc37d

Browse files
authored
Add a node to InvalidGenerationSourceError (#670)
Allow attempting to find the source location from an AstNode as an alternative to finding it from an Element.
1 parent 071eb84 commit c6fc37d

File tree

5 files changed

+66
-8
lines changed

5 files changed

+66
-8
lines changed

source_gen/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
## 1.3.3-wip
1+
## 1.4.0-wip
22

33
- Require Dart 3.0
4+
- Add a `node` argument to `InvalidGenerationSourceError` to allow finding the
5+
source location from an `AstNode` over an `Element`.
46

57
## 1.3.2
68

source_gen/lib/src/generator.dart

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'dart:async';
66

7+
import 'package:analyzer/dart/ast/ast.dart';
78
import 'package:analyzer/dart/element/element.dart';
89
import 'package:build/build.dart';
910

@@ -41,18 +42,30 @@ class InvalidGenerationSourceError extends Error {
4142

4243
/// The code element associated with this error.
4344
///
44-
/// May be `null` if the error had no associated element.
45+
/// May be `null` if the error had no associated element, or if the location
46+
/// was passed with [node].
4547
final Element? element;
4648

47-
InvalidGenerationSourceError(this.message, {this.todo = '', this.element});
49+
/// The AST Node associated with this error.
50+
///
51+
/// May be `null` if the error has no associated node in the input source
52+
/// code, or if the location was passed with [element].
53+
final AstNode? node;
54+
55+
InvalidGenerationSourceError(
56+
this.message, {
57+
this.todo = '',
58+
this.element,
59+
this.node,
60+
});
4861

4962
@override
5063
String toString() {
5164
final buffer = StringBuffer(message);
5265

53-
if (element != null) {
66+
if (element case final element?) {
5467
try {
55-
final span = spanForElement(element!);
68+
final span = spanForElement(element);
5669
buffer
5770
..writeln()
5871
..writeln(span.start.toolString)
@@ -66,6 +79,20 @@ class InvalidGenerationSourceError extends Error {
6679
}
6780
}
6881

82+
if (node case final node?) {
83+
try {
84+
final span = spanForNode(node);
85+
buffer
86+
..writeln()
87+
..writeln(span.start.toolString)
88+
..write(span.highlight());
89+
} catch (_) {
90+
buffer
91+
..writeln()
92+
..writeln('Cause: $node');
93+
}
94+
}
95+
6996
return buffer.toString();
7097
}
7198
}

source_gen/lib/src/span_for_element.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analyzer/dart/ast/ast.dart';
56
import 'package:analyzer/dart/element/element.dart';
67
import 'package:source_span/source_span.dart';
78

@@ -51,3 +52,13 @@ SourceSpan spanForElement(Element element, [SourceFile? file]) {
5152

5253
return file.span(element.nameOffset, element.nameOffset + element.nameLength);
5354
}
55+
56+
/// Returns a source span that spans the location where [node] is written.
57+
SourceSpan spanForNode(AstNode node) {
58+
final unit = node.thisOrAncestorOfType<CompilationUnit>()!;
59+
final element = unit.declaredElement!;
60+
final contents = element.source.contents.data;
61+
final url = assetToPackageUrl(element.source.uri);
62+
final file = SourceFile.fromString(contents, url: url);
63+
return file.span(node.offset, node.offset + node.length);
64+
}

source_gen/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: source_gen
2-
version: 1.3.3-wip
2+
version: 1.4.0-wip
33
description: >-
44
Source code generation builders and utilities for the Dart build system
55
repository: https://github.com/dart-lang/source_gen/tree/master/source_gen

source_gen/test/span_for_element_test.dart

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
import 'package:analyzer/dart/element/element.dart';
66
import 'package:build/build.dart';
77
import 'package:build_test/build_test.dart';
8-
import 'package:source_gen/source_gen.dart';
8+
import 'package:source_gen/src/span_for_element.dart';
99
import 'package:term_glyph/term_glyph.dart' as glyph;
1010
import 'package:test/test.dart';
1111

1212
void main() {
1313
glyph.ascii = true;
1414
late LibraryElement library;
15+
late Resolver resolver;
1516

1617
setUpAll(() async {
1718
library = await resolveSource(
@@ -28,7 +29,10 @@ abstract class Example implements List {
2829
}
2930
}
3031
''',
31-
(resolver) async => (await resolver.findLibraryByName('test_lib'))!,
32+
(r) async {
33+
resolver = r;
34+
return (await resolver.findLibraryByName('test_lib'))!;
35+
},
3236
inputId: AssetId('test_lib', 'lib/test_lib.dart'),
3337
);
3438
});
@@ -96,4 +100,18 @@ line 7, column 11 of package:test_lib/test_lib.dart: Here it is
96100
'""",
97101
);
98102
});
103+
104+
test('highlights based on AstNode source location', () async {
105+
final element = library.getClass('Example')!.getField('field')!.declaration;
106+
final node = (await resolver.astNodeFor(element, resolve: true))!;
107+
expect(
108+
spanForNode(node).message('Here it is'),
109+
r"""
110+
line 6, column 7 of package:test_lib/test_lib.dart: Here it is
111+
,
112+
6 | int field;
113+
| ^^^^^
114+
'""",
115+
);
116+
});
99117
}

0 commit comments

Comments
 (0)