mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:21:07 +00:00
f5a3bce734
Previously, when encountering identifiers in metadata on a class's type parameter, the analyzer would resolve them using the type parameter scope, but then fall back on using implicit `this`. The CFE would resolve them using the class body scope. In both cases, the end result was that the annotation could refer to static class members. This change brings the behavior of both the analyzer and the CFE in line with the spec, by preventing the use of implicit `this` in these annotations, and resolving them in the type parameter scope. This is not expected to break any code in practice, because annotations on type parameters are rare, as are annotations referring to static class members, and the overlap between these two should be negligibly small. Fixes https://github.com/dart-lang/language/issues/1790. Bug: https://github.com/dart-lang/language/issues/1790 Change-Id: Ibe5a421e04a53d29074a8b1509e1390658ed72e5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/210040 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
66 lines
2 KiB
Dart
66 lines
2 KiB
Dart
// Copyright (c) 2014, 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.
|
|
|
|
library test.metadata_scope;
|
|
|
|
import 'dart:mirrors';
|
|
import 'package:expect/expect.dart';
|
|
|
|
class Annotation {
|
|
final contents;
|
|
const Annotation(this.contents);
|
|
toString() => "Annotation($contents)";
|
|
}
|
|
|
|
// Note there is no compile-time constant 'foo' in scope. In particular, A.foo
|
|
// is not in scope here.
|
|
@Annotation(foo) //# 01: compile-time error
|
|
class A<
|
|
@Annotation(foo) //# 02: compile-time error
|
|
T> {
|
|
@Annotation(foo)
|
|
static foo() {}
|
|
|
|
@Annotation(foo)
|
|
static bar() {}
|
|
}
|
|
|
|
@Annotation(B.foo)
|
|
class B<@Annotation(B.foo) T> {
|
|
@Annotation(B.foo)
|
|
static foo() {}
|
|
|
|
@Annotation(B.foo)
|
|
static bar() {}
|
|
}
|
|
|
|
baz() {}
|
|
|
|
// Note the top-level function baz is in scope here, not C.baz.
|
|
@Annotation(baz)
|
|
class C<@Annotation(baz) T> {
|
|
@Annotation(baz)
|
|
static baz() {}
|
|
}
|
|
|
|
checkMetadata(DeclarationMirror mirror, List expectedMetadata) {
|
|
Expect.listEquals(expectedMetadata.map(reflect).toList(), mirror.metadata);
|
|
}
|
|
|
|
main() {
|
|
reflectClass(A).metadata;
|
|
checkMetadata(reflectClass(A).declarations[#T]!, [const Annotation(A.foo)]);
|
|
checkMetadata(reflectClass(A).declarations[#foo]!, [const Annotation(A.foo)]);
|
|
checkMetadata(reflectClass(A).declarations[#bar]!, [const Annotation(A.foo)]);
|
|
checkMetadata(reflectClass(B), [const Annotation(B.foo)]);
|
|
checkMetadata(reflectClass(B).declarations[#T]!, [const Annotation(B.foo)]);
|
|
checkMetadata(reflectClass(B).declarations[#foo]!, [const Annotation(B.foo)]);
|
|
checkMetadata(reflectClass(B).declarations[#bar]!, [const Annotation(B.foo)]);
|
|
// The top-level function baz, not C.baz.
|
|
checkMetadata(reflectClass(C), [const Annotation(baz)]);
|
|
// C.baz, not the top-level function baz.
|
|
checkMetadata(reflectClass(C).declarations[#T]!, [const Annotation(C.baz)]);
|
|
checkMetadata(reflectClass(C).declarations[#baz]!, [const Annotation(C.baz)]);
|
|
}
|