Skip to content

Commit cda3659

Browse files
Dmitry Stefantsovcommit-bot@chromium.org
authored andcommitted
[fasta] Handle annotations on formals of typedefs
Fixes #33799. Bug: http://dartbug.com/33799 Change-Id: I5808e45839cece468d890dcaf344df0d4b249a3c Reviewed-on: https://dart-review.googlesource.com/65701 Commit-Queue: Dmitry Stefantsov <[email protected]> Reviewed-by: Jens Johansen <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]> Reviewed-by: Dan Rubel <[email protected]>
1 parent 46743f3 commit cda3659

19 files changed

+255
-33
lines changed

pkg/front_end/lib/src/fasta/kernel/body_builder.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,14 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
855855
List<Expression> finishMetadata(TreeNode parent) {
856856
List<Expression> expressions = pop();
857857
_typeInferrer.inferMetadata(this, expressions);
858+
859+
// The invocation of [resolveRedirectingFactoryTargets] below may change the
860+
// root nodes of the annotation expressions. We need to have a parent of
861+
// the annotation nodes before the resolution is performed, to collect and
862+
// return them later. If [parent] is not provided, [temporaryParent] is
863+
// used.
864+
ListLiteral temporaryParent;
865+
858866
if (parent is Class) {
859867
for (Expression expression in expressions) {
860868
parent.addAnnotation(expression);
@@ -887,9 +895,11 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
887895
for (Expression expression in expressions) {
888896
parent.addAnnotation(expression);
889897
}
898+
} else {
899+
temporaryParent = new ListLiteral(expressions);
890900
}
891901
resolveRedirectingFactoryTargets();
892-
return expressions;
902+
return temporaryParent != null ? temporaryParent.expressions : expressions;
893903
}
894904

895905
@override

pkg/front_end/lib/src/fasta/source/diet_listener.dart

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import 'package:kernel/ast.dart'
1313
LibraryDependency,
1414
LibraryPart,
1515
Node,
16-
TreeNode;
16+
TreeNode,
17+
VariableDeclaration;
1718

1819
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
1920

@@ -35,6 +36,12 @@ import '../fasta_codes.dart'
3536

3637
import '../kernel/kernel_body_builder.dart' show KernelBodyBuilder;
3738

39+
import '../kernel/kernel_formal_parameter_builder.dart'
40+
show KernelFormalParameterBuilder;
41+
42+
import '../kernel/kernel_function_type_alias_builder.dart'
43+
show KernelFunctionTypeAliasBuilder;
44+
3845
import '../kernel/kernel_procedure_builder.dart'
3946
show KernelRedirectingFactoryBuilder;
4047

@@ -220,6 +227,38 @@ class DietListener extends StackListener {
220227

221228
Declaration typedefBuilder = lookupBuilder(typedefKeyword, null, name);
222229
parseMetadata(typedefBuilder, metadata, typedefBuilder.target);
230+
if (typedefBuilder is KernelFunctionTypeAliasBuilder &&
231+
typedefBuilder.type != null &&
232+
typedefBuilder.type.formals != null) {
233+
for (int i = 0; i < typedefBuilder.type.formals.length; ++i) {
234+
KernelFormalParameterBuilder formal = typedefBuilder.type.formals[i];
235+
List<MetadataBuilder> metadata = formal.metadata;
236+
if (metadata != null && metadata.length > 0) {
237+
// [parseMetadata] is using [Parser.parseMetadataStar] under the hood,
238+
// so we only need the offset of the first annotation.
239+
Token metadataToken =
240+
tokenForOffset(typedefKeyword, endToken, metadata[0].charOffset);
241+
List<Expression> annotations =
242+
parseMetadata(typedefBuilder, metadataToken, null);
243+
if (formal.isPositional) {
244+
VariableDeclaration parameter =
245+
typedefBuilder.target.positionalParameters[i];
246+
for (Expression annotation in annotations) {
247+
parameter.addAnnotation(annotation);
248+
}
249+
} else {
250+
for (VariableDeclaration named
251+
in typedefBuilder.target.namedParameters) {
252+
if (named.name == formal.name) {
253+
for (Expression annotation in annotations) {
254+
named.addAnnotation(annotation);
255+
}
256+
}
257+
}
258+
}
259+
}
260+
}
261+
}
223262

224263
checkEmpty(typedefKeyword.charOffset);
225264
}
@@ -833,6 +872,22 @@ class DietListener extends StackListener {
833872
return null;
834873
}
835874

875+
/// Returns [Token] found between [start] (inclusive) and [end]
876+
/// (non-inclusive) that has its [Token.charOffset] equal to [offset]. If
877+
/// there is no such token, null is returned.
878+
Token tokenForOffset(Token start, Token end, int offset) {
879+
if (offset < start.charOffset || offset >= end.charOffset) {
880+
return null;
881+
}
882+
while (start != end) {
883+
if (offset == start.charOffset) {
884+
return start;
885+
}
886+
start = start.next;
887+
}
888+
return null;
889+
}
890+
836891
/// Returns list of [Token]s found between [start] (inclusive) and [end]
837892
/// (non-inclusive) that correspond to [offsets]. If there's no token between
838893
/// [start] and [end] for the given offset, the corresponding item in the
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// This test checks that the compiler handles annotations on formals of
6+
// typedefs.
7+
8+
const int foo = 21;
9+
const int bar = 42;
10+
const int baz = 84;
11+
12+
typedef void F(@foo int x, num y, {@bar @baz String z, Object w});
13+
typedef void G(@foo int a, num b, [@bar @baz String c, Object d]);
14+
15+
main() {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef F = (@self::foo core::int x, core::num y, {@self::bar @self::baz core::String z, core::Object w}) → void;
6+
typedef G = (@self::foo core::int a, core::num b, [@self::bar @self::baz core::String c, core::Object d]) → void;
7+
static const field core::int foo = 21;
8+
static const field core::int bar = 42;
9+
static const field core::int baz = 84;
10+
static method main() → dynamic {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef F = (@self::foo core::int x, core::num y, {@self::bar @self::baz core::String z, core::Object w}) → void;
6+
typedef G = (@self::foo core::int a, core::num b, [@self::bar @self::baz core::String c, core::Object d]) → void;
7+
static const field core::int foo = 21;
8+
static const field core::int bar = 42;
9+
static const field core::int baz = 84;
10+
static method main() → dynamic {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef F = (core::int, core::num, {w: core::Object, z: core::String}) → void;
6+
typedef G = (core::int, core::num, [core::String, core::Object]) → void;
7+
static const field core::int foo;
8+
static const field core::int bar;
9+
static const field core::int baz;
10+
static method main() → dynamic
11+
;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef F = (@self::foo core::int x, core::num y, {@self::bar @self::baz core::String z, core::Object w}) → void;
6+
typedef G = (@self::foo core::int a, core::num b, [@self::bar @self::baz core::String c, core::Object d]) → void;
7+
static const field core::int foo = 21;
8+
static const field core::int bar = 42;
9+
static const field core::int baz = 84;
10+
static method main() → dynamic {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef F = (@self::foo core::int x, core::num y, {@self::bar @self::baz core::String z, core::Object w}) → void;
6+
typedef G = (@self::foo core::int a, core::num b, [@self::bar @self::baz core::String c, core::Object d]) → void;
7+
static const field core::int foo = 21;
8+
static const field core::int bar = 42;
9+
static const field core::int baz = 84;
10+
static method main() → dynamic {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// This test checks that the annotation on a formal parameter of a typedef is
6+
// resolved to the top-level constant, and not to the parameter itself in case
7+
// of a name match.
8+
9+
const int app = 0;
10+
11+
typedef int F(@app int app);
12+
13+
main() {}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
typedef F = (@self::app core::int app) → core::int;
6+
static const field core::int app = 0;
7+
static method main() → dynamic {}

0 commit comments

Comments
 (0)