Support for generic annotations. (#994)
This change provides enough support to avoid a crash, ensure that
generic annotations are preserved by the formatter, and format them nicely.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cd2d4cf..fcc6c1d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 1.3.14
+
+* Add support for generic annotations.
+
# 1.3.13
- Allow the latest version of `package:analyzer`.
diff --git a/lib/src/dart_formatter.dart b/lib/src/dart_formatter.dart
index aed309a..e842bb2 100644
--- a/lib/src/dart_formatter.dart
+++ b/lib/src/dart_formatter.dart
@@ -91,7 +91,8 @@
// TODO(paulberry): consider plumbing in experiment enable flags from the
// command line.
var featureSet = FeatureSet.fromEnableFlags2(
- sdkLanguageVersion: Version(2, 10, 0), flags: ['non-nullable']);
+ sdkLanguageVersion: Version(2, 10, 0),
+ flags: ['non-nullable', 'generic-metadata']);
var inputOffset = 0;
var text = source.text;
diff --git a/lib/src/source_visitor.dart b/lib/src/source_visitor.dart
index 64be1a5..ebbae38 100644
--- a/lib/src/source_visitor.dart
+++ b/lib/src/source_visitor.dart
@@ -297,13 +297,20 @@
void visitAnnotation(Annotation node) {
token(node.atSign);
visit(node.name);
+
+ builder.nestExpression();
+ visit(node.typeArguments);
token(node.period);
visit(node.constructorName);
- // Metadata annotations are always const contexts.
- _constNesting++;
- visit(node.arguments);
- _constNesting--;
+ if (node.arguments != null) {
+ // Metadata annotations are always const contexts.
+ _constNesting++;
+ visitArgumentList(node.arguments, nestExpression: false);
+ _constNesting--;
+ }
+
+ builder.unnest();
}
/// Visits an argument list.
diff --git a/pubspec.yaml b/pubspec.yaml
index 177e313..5118209 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: dart_style
# Note: See tool/grind.dart for how to bump the version.
-version: 1.3.13
+version: 1.3.14-dev
description: >-
Opinionated, automatic Dart source code formatter.
Provides an API and a CLI tool.
diff --git a/test/splitting/annotations.unit b/test/splitting/annotations.unit
new file mode 100644
index 0000000..da72c4c
--- /dev/null
+++ b/test/splitting/annotations.unit
@@ -0,0 +1,95 @@
+40 columns |
+>>> complex annotation that all fits on one line
+@a.B<C,D>(e,f,g) int i = 0;
+<<<
+@a.B<C, D>(e, f, g)
+int i = 0;
+>>> prefer to split between args even when they all fit on next line
+@BigLongClassName<First, Second, Third>() int i = 0;
+<<<
+@BigLongClassName<First, Second,
+ Third>()
+int i = 0;
+>>> split before first if needed
+@BigLongClassName<FirstTypeArgumentIsLong, Second>() int i = 0;
+<<<
+@BigLongClassName<
+ FirstTypeArgumentIsLong, Second>()
+int i = 0;
+>>> split in middle if fit in two lines
+@BigLongClassName<First, Second, Third, Fourth, Fifth, Sixth, Seventh>() int i = 0;
+<<<
+@BigLongClassName<First, Second, Third,
+ Fourth, Fifth, Sixth, Seventh>()
+int i = 0;
+>>> split one per line if they don't fit in two lines
+@BigLongClassName<First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth>() int i = 0;
+<<<
+@BigLongClassName<
+ First,
+ Second,
+ Third,
+ Fourth,
+ Fifth,
+ Sixth,
+ Seventh,
+ Eighth>()
+int i = 0;
+>>> prefers to not split at type arguments
+@SomeBigClass<
+ TypeArgument>(valueArgument)
+int i = 0;
+<<<
+@SomeBigClass<TypeArgument>(
+ valueArgument)
+int i = 0;
+>>> split both type and value arguments
+@SomeBigClass<First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth>(first, second, third, fourth, fifth, sixth, seventh, eighth) int i = 0;
+<<<
+@SomeBigClass<
+ First,
+ Second,
+ Third,
+ Fourth,
+ Fifth,
+ Sixth,
+ Seventh,
+ Eighth>(
+ first,
+ second,
+ third,
+ fourth,
+ fifth,
+ sixth,
+ seventh,
+ eighth)
+int i = 0;
+>>> prefer to split at arguments rather than prefix
+@veryLongPrefix.VeryLongClassName<VeryLongTypeArgument,OtherVeryLongTypeArgument>(veryLongArgument,otherVeryLongArgument,thirdVeryLongArgument) int i = 0;
+<<<
+@veryLongPrefix.VeryLongClassName<
+ VeryLongTypeArgument,
+ OtherVeryLongTypeArgument>(
+ veryLongArgument,
+ otherVeryLongArgument,
+ thirdVeryLongArgument)
+int i = 0;
+>>> nested type arguments, no splitting required
+@A<B<C,D>,E<F,G>>() int i = 0;
+<<<
+@A<B<C, D>, E<F, G>>()
+int i = 0;
+>>> nested type arguments, split at outer level when possible
+@Aaaa<Bbbb<Cccc,Dddd>,Eeee<Ffff,Gggg>>() int i = 0;
+<<<
+@Aaaa<Bbbb<Cccc, Dddd>,
+ Eeee<Ffff, Gggg>>()
+int i = 0;
+>>> nested type arguments, split at inner level when necessary
+@Aaaaaaaaa<Bbbbbbbbbbb<Ccccccccccc,Ddddddddddd>,Eeeeeeeee<Fffffffff,Ggggggggg>>() int i = 0;
+<<<
+@Aaaaaaaaa<
+ Bbbbbbbbbbb<Ccccccccccc,
+ Ddddddddddd>,
+ Eeeeeeeee<Fffffffff, Ggggggggg>>()
+int i = 0;
diff --git a/test/whitespace/metadata.unit b/test/whitespace/metadata.unit
index c25e98f..87ed0b7 100644
--- a/test/whitespace/metadata.unit
+++ b/test/whitespace/metadata.unit
@@ -380,4 +380,24 @@
class C {
@meta
abstract var x;
-}
\ No newline at end of file
+}
+>>> annotation with type arguments
+@A<int,String>()int x;
+<<<
+@A<int, String>()
+int x;
+>>>
+@prefix.A<int,String>()int x;
+<<<
+@prefix.A<int, String>()
+int x;
+>>>
+@A<int,String>.constructor()int x;
+<<<
+@A<int, String>.constructor()
+int x;
+>>>
+@prefix.A<int,String>.constructor()int x;
+<<<
+@prefix.A<int, String>.constructor()
+int x;