[kernel] Add an option to the cloner for cloning annotations
Fixes #33099
Bug: http://dartbug.com/33099
Change-Id: I291e75fa49fb6bf62557cfeab0c874c5de9b618d
Reviewed-on: https://dart-review.googlesource.com/57264
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Kevin Millikin <kmillikin@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
index d331200..efd77e8 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
@@ -427,8 +427,9 @@
KernelTarget target, Procedure procedure, ClassHierarchy hierarchy) {
CloneWithoutBody cloner = new CloneWithoutBody(
typeSubstitution: getSubstitutionMap(
- hierarchy.getClassAsInstanceOf(cls, procedure.enclosingClass)));
- Procedure cloned = cloner.clone(procedure);
+ hierarchy.getClassAsInstanceOf(cls, procedure.enclosingClass)),
+ cloneAnnotations: false);
+ Procedure cloned = cloner.clone(procedure)..isExternal = false;
transformProcedureToNoSuchMethodForwarder(noSuchMethod, target, cloned);
cls.procedures.add(cloned);
cloned.parent = cls;
diff --git a/pkg/front_end/testcases/bug33099.dart b/pkg/front_end/testcases/bug33099.dart
new file mode 100644
index 0000000..25fd24e
--- /dev/null
+++ b/pkg/front_end/testcases/bug33099.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2018, 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 'dart:mirrors';
+
+const _FailingTest failingTest = const _FailingTest();
+
+class _FailingTest {
+ const _FailingTest();
+}
+
+class MyTest {
+ @failingTest
+ void foo() {}
+}
+
+class MyTest2 extends Object with MyTest {}
+
+main() {
+ ClassMirror classMirror = reflectClass(MyTest2);
+ classMirror.instanceMembers
+ .forEach((Symbol symbol, MethodMirror memberMirror) {
+ if (memberMirror.simpleName == #foo) {
+ print(memberMirror);
+ print(_hasFailingTestAnnotation(memberMirror));
+ }
+ });
+}
+
+bool _hasFailingTestAnnotation(MethodMirror method) {
+ var r = _hasAnnotationInstance(method, failingTest);
+ print('[_hasFailingTestAnnotation] $method $r');
+ return r;
+}
+
+bool _hasAnnotationInstance(DeclarationMirror declaration, instance) =>
+ declaration.metadata.any((InstanceMirror annotation) {
+ print('annotation: ${annotation.reflectee}');
+ return identical(annotation.reflectee, instance);
+ });
diff --git a/pkg/front_end/testcases/bug33099.dart.direct.expect b/pkg/front_end/testcases/bug33099.dart.direct.expect
new file mode 100644
index 0000000..ac82f35
--- /dev/null
+++ b/pkg/front_end/testcases/bug33099.dart.direct.expect
@@ -0,0 +1,44 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:mirrors" as mir;
+
+class _FailingTest extends core::Object {
+ const constructor •() → void
+ : super core::Object::•()
+ ;
+}
+class MyTest extends core::Object {
+ synthetic constructor •() → void
+ : super core::Object::•()
+ ;
+ @self::failingTest
+ method foo() → void {}
+}
+abstract class _MyTest2&Object&MyTest = core::Object with self::MyTest {
+}
+class MyTest2 extends self::_MyTest2&Object&MyTest {
+ synthetic constructor •() → void
+ : super core::Object::•()
+ ;
+}
+static const field self::_FailingTest failingTest = const self::_FailingTest::•();
+static method main() → dynamic {
+ mir::ClassMirror classMirror = mir::reflectClass(self::MyTest2);
+ classMirror.instanceMembers.forEach((core::Symbol symbol, mir::MethodMirror memberMirror) → dynamic {
+ if(memberMirror.simpleName.==(#foo)) {
+ core::print(memberMirror);
+ core::print(self::_hasFailingTestAnnotation(memberMirror));
+ }
+ });
+}
+static method _hasFailingTestAnnotation(mir::MethodMirror method) → core::bool {
+ dynamic r = self::_hasAnnotationInstance(method, self::failingTest);
+ core::print("[_hasFailingTestAnnotation] ${method} ${r}");
+ return r;
+}
+static method _hasAnnotationInstance(mir::DeclarationMirror declaration, dynamic instance) → core::bool
+ return declaration.metadata.any((mir::InstanceMirror annotation) → dynamic {
+ core::print("annotation: ${annotation.reflectee}");
+ return core::identical(annotation.reflectee, instance);
+ });
diff --git a/pkg/front_end/testcases/bug33099.dart.direct.transformed.expect b/pkg/front_end/testcases/bug33099.dart.direct.transformed.expect
new file mode 100644
index 0000000..d26b033
--- /dev/null
+++ b/pkg/front_end/testcases/bug33099.dart.direct.transformed.expect
@@ -0,0 +1,49 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:mirrors" as mir;
+
+class _FailingTest extends core::Object {
+ const constructor •() → void
+ : super core::Object::•()
+ ;
+}
+class MyTest extends core::Object {
+ synthetic constructor •() → void
+ : super core::Object::•()
+ ;
+ @self::failingTest
+ method foo() → void {}
+}
+abstract class _MyTest2&Object&MyTest extends core::Object implements self::MyTest {
+ synthetic constructor •() → void
+ : super core::Object::•()
+ ;
+ @self::failingTest
+ method foo() → void {}
+}
+class MyTest2 extends self::_MyTest2&Object&MyTest {
+ synthetic constructor •() → void
+ : super core::Object::•()
+ ;
+}
+static const field self::_FailingTest failingTest = const self::_FailingTest::•();
+static method main() → dynamic {
+ mir::ClassMirror classMirror = mir::reflectClass(self::MyTest2);
+ classMirror.instanceMembers.forEach((core::Symbol symbol, mir::MethodMirror memberMirror) → dynamic {
+ if(memberMirror.simpleName.==(#foo)) {
+ core::print(memberMirror);
+ core::print(self::_hasFailingTestAnnotation(memberMirror));
+ }
+ });
+}
+static method _hasFailingTestAnnotation(mir::MethodMirror method) → core::bool {
+ dynamic r = self::_hasAnnotationInstance(method, self::failingTest);
+ core::print("[_hasFailingTestAnnotation] ${method} ${r}");
+ return r;
+}
+static method _hasAnnotationInstance(mir::DeclarationMirror declaration, dynamic instance) → core::bool
+ return declaration.metadata.any((mir::InstanceMirror annotation) → dynamic {
+ core::print("annotation: ${annotation.reflectee}");
+ return core::identical(annotation.reflectee, instance);
+ });
diff --git a/pkg/front_end/testcases/bug33099.dart.outline.expect b/pkg/front_end/testcases/bug33099.dart.outline.expect
new file mode 100644
index 0000000..9d360a0
--- /dev/null
+++ b/pkg/front_end/testcases/bug33099.dart.outline.expect
@@ -0,0 +1,28 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:mirrors" as mir;
+
+class _FailingTest extends core::Object {
+ const constructor •() → void
+ ;
+}
+class MyTest extends core::Object {
+ synthetic constructor •() → void
+ ;
+ method foo() → void
+ ;
+}
+abstract class _MyTest2&Object&MyTest = core::Object with self::MyTest {
+}
+class MyTest2 extends self::_MyTest2&Object&MyTest {
+ synthetic constructor •() → void
+ ;
+}
+static const field self::_FailingTest failingTest;
+static method main() → dynamic
+ ;
+static method _hasFailingTestAnnotation(mir::MethodMirror method) → core::bool
+ ;
+static method _hasAnnotationInstance(mir::DeclarationMirror declaration, dynamic instance) → core::bool
+ ;
diff --git a/pkg/front_end/testcases/bug33099.dart.strong.expect b/pkg/front_end/testcases/bug33099.dart.strong.expect
new file mode 100644
index 0000000..4119f1c
--- /dev/null
+++ b/pkg/front_end/testcases/bug33099.dart.strong.expect
@@ -0,0 +1,44 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:mirrors" as mir;
+
+class _FailingTest extends core::Object {
+ const constructor •() → void
+ : super core::Object::•()
+ ;
+}
+class MyTest extends core::Object {
+ synthetic constructor •() → void
+ : super core::Object::•()
+ ;
+ @self::failingTest
+ method foo() → void {}
+}
+abstract class _MyTest2&Object&MyTest = core::Object with self::MyTest {
+}
+class MyTest2 extends self::_MyTest2&Object&MyTest {
+ synthetic constructor •() → void
+ : super core::Object::•()
+ ;
+}
+static const field self::_FailingTest failingTest = const self::_FailingTest::•();
+static method main() → dynamic {
+ mir::ClassMirror classMirror = mir::reflectClass(self::MyTest2);
+ classMirror.{mir::ClassMirror::instanceMembers}.{core::Map::forEach}((core::Symbol symbol, mir::MethodMirror memberMirror) → core::Null {
+ if(memberMirror.{mir::DeclarationMirror::simpleName}.{core::Symbol::==}(#foo)) {
+ core::print(memberMirror);
+ core::print(self::_hasFailingTestAnnotation(memberMirror));
+ }
+ });
+}
+static method _hasFailingTestAnnotation(mir::MethodMirror method) → core::bool {
+ core::bool r = self::_hasAnnotationInstance(method, self::failingTest);
+ core::print("[_hasFailingTestAnnotation] ${method} ${r}");
+ return r;
+}
+static method _hasAnnotationInstance(mir::DeclarationMirror declaration, dynamic instance) → core::bool
+ return declaration.{mir::DeclarationMirror::metadata}.{core::Iterable::any}((mir::InstanceMirror annotation) → core::bool {
+ core::print("annotation: ${annotation.{mir::InstanceMirror::reflectee}}");
+ return core::identical(annotation.{mir::InstanceMirror::reflectee}, instance);
+ });
diff --git a/pkg/front_end/testcases/bug33099.dart.strong.transformed.expect b/pkg/front_end/testcases/bug33099.dart.strong.transformed.expect
new file mode 100644
index 0000000..072ae37
--- /dev/null
+++ b/pkg/front_end/testcases/bug33099.dart.strong.transformed.expect
@@ -0,0 +1,49 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:mirrors" as mir;
+
+class _FailingTest extends core::Object {
+ const constructor •() → void
+ : super core::Object::•()
+ ;
+}
+class MyTest extends core::Object {
+ synthetic constructor •() → void
+ : super core::Object::•()
+ ;
+ @self::failingTest
+ method foo() → void {}
+}
+abstract class _MyTest2&Object&MyTest extends core::Object implements self::MyTest {
+ synthetic constructor •() → void
+ : super core::Object::•()
+ ;
+ @self::failingTest
+ method foo() → void {}
+}
+class MyTest2 extends self::_MyTest2&Object&MyTest {
+ synthetic constructor •() → void
+ : super core::Object::•()
+ ;
+}
+static const field self::_FailingTest failingTest = const self::_FailingTest::•();
+static method main() → dynamic {
+ mir::ClassMirror classMirror = mir::reflectClass(self::MyTest2);
+ classMirror.{mir::ClassMirror::instanceMembers}.{core::Map::forEach}((core::Symbol symbol, mir::MethodMirror memberMirror) → core::Null {
+ if(memberMirror.{mir::DeclarationMirror::simpleName}.{core::Symbol::==}(#foo)) {
+ core::print(memberMirror);
+ core::print(self::_hasFailingTestAnnotation(memberMirror));
+ }
+ });
+}
+static method _hasFailingTestAnnotation(mir::MethodMirror method) → core::bool {
+ core::bool r = self::_hasAnnotationInstance(method, self::failingTest);
+ core::print("[_hasFailingTestAnnotation] ${method} ${r}");
+ return r;
+}
+static method _hasAnnotationInstance(mir::DeclarationMirror declaration, dynamic instance) → core::bool
+ return declaration.{mir::DeclarationMirror::metadata}.{core::Iterable::any}((mir::InstanceMirror annotation) → core::bool {
+ core::print("annotation: ${annotation.{mir::InstanceMirror::reflectee}}");
+ return core::identical(annotation.{mir::InstanceMirror::reflectee}, instance);
+ });
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index 3a461aa1..91f5fd6 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -20,8 +20,16 @@
<LabeledStatement, LabeledStatement>{};
final Map<SwitchCase, SwitchCase> switchCases = <SwitchCase, SwitchCase>{};
final Map<TypeParameter, DartType> typeSubstitution;
+ bool cloneAnnotations;
- CloneVisitor({Map<TypeParameter, DartType> typeSubstitution})
+ /// Creates an instance of the cloning visitor for Kernel ASTs.
+ ///
+ /// The boolean value of [cloneAnnotations] tells if the annotations on the
+ /// outline elements in the source AST should be cloned to the target AST. The
+ /// annotations in procedure bodies are cloned unconditionally.
+ CloneVisitor(
+ {Map<TypeParameter, DartType> typeSubstitution,
+ this.cloneAnnotations = true})
: this.typeSubstitution = ensureMutable(typeSubstitution);
static Map<TypeParameter, DartType> ensureMutable(
@@ -395,6 +403,9 @@
return variables[node] = new VariableDeclaration(node.name,
initializer: cloneOptional(node.initializer),
type: visitType(node.type))
+ ..annotations = cloneAnnotations && !node.annotations.isEmpty
+ ? node.annotations.map(clone).toList()
+ : const <Expression>[]
..flags = node.flags;
}
@@ -413,6 +424,9 @@
initializers: node.initializers.map(clone).toList(),
transformerFlags: node.transformerFlags,
fileUri: _activeFileUri)
+ ..annotations = cloneAnnotations && !node.annotations.isEmpty
+ ? node.annotations.map(clone).toList()
+ : const <Expression>[]
..fileOffset = _cloneFileOffset(node.fileOffset)
..fileEndOffset = _cloneFileOffset(node.fileEndOffset);
}
@@ -423,6 +437,9 @@
fileUri: _activeFileUri,
forwardingStubSuperTarget: node.forwardingStubSuperTarget,
forwardingStubInterfaceTarget: node.forwardingStubInterfaceTarget)
+ ..annotations = cloneAnnotations && !node.annotations.isEmpty
+ ? node.annotations.map(clone).toList()
+ : const <Expression>[]
..fileOffset = _cloneFileOffset(node.fileOffset)
..fileEndOffset = _cloneFileOffset(node.fileEndOffset)
..flags = node.flags;
@@ -440,6 +457,9 @@
hasImplicitSetter: node.hasImplicitSetter,
transformerFlags: node.transformerFlags,
fileUri: _activeFileUri)
+ ..annotations = cloneAnnotations && !node.annotations.isEmpty
+ ? node.annotations.map(clone).toList()
+ : const <Expression>[]
..fileOffset = _cloneFileOffset(node.fileOffset)
..fileEndOffset = _cloneFileOffset(node.fileEndOffset)
..flags = node.flags;
@@ -456,7 +476,10 @@
positionalParameters: node.positionalParameters.map(clone).toList(),
namedParameters: node.namedParameters.map(clone).toList(),
requiredParameterCount: node.requiredParameterCount,
- fileUri: _activeFileUri);
+ fileUri: _activeFileUri)
+ ..annotations = cloneAnnotations && !node.annotations.isEmpty
+ ? node.annotations.map(clone).toList()
+ : const <Expression>[];
}
visitTypeParameter(TypeParameter node) {
@@ -466,10 +489,22 @@
if (node.defaultType != null) {
newNode.defaultType = visitType(node.defaultType);
}
- return newNode..flags = node.flags;
+ return newNode
+ ..annotations = cloneAnnotations && !node.annotations.isEmpty
+ ? node.annotations.map(clone).toList()
+ : const <Expression>[]
+ ..flags = node.flags;
}
- TreeNode cloneFunctionNodeBody(FunctionNode node) => cloneOptional(node.body);
+ TreeNode cloneFunctionNodeBody(FunctionNode node) {
+ bool savedCloneAnnotations = this.cloneAnnotations;
+ try {
+ this.cloneAnnotations = true;
+ return cloneOptional(node.body);
+ } finally {
+ this.cloneAnnotations = savedCloneAnnotations;
+ }
+ }
visitFunctionNode(FunctionNode node) {
var typeParameters = node.typeParameters.map(clone).toList();
@@ -584,8 +619,12 @@
}
class CloneWithoutBody extends CloneVisitor {
- CloneWithoutBody({Map<TypeParameter, DartType> typeSubstitution})
- : super(typeSubstitution: typeSubstitution);
+ CloneWithoutBody(
+ {Map<TypeParameter, DartType> typeSubstitution,
+ bool cloneAnnotations = true})
+ : super(
+ typeSubstitution: typeSubstitution,
+ cloneAnnotations: cloneAnnotations);
@override
TreeNode cloneFunctionNodeBody(FunctionNode node) => null;