diff --git a/pkg/front_end/test/incremental_suite.dart b/pkg/front_end/test/incremental_suite.dart index b801d37adb7..2479d56a2bc 100644 --- a/pkg/front_end/test/incremental_suite.dart +++ b/pkg/front_end/test/incremental_suite.dart @@ -1585,7 +1585,10 @@ class NewWorldTest { compiler.getFilteredInvalidatedImportUrisForTesting(invalidated); if (world.invalidate != null) { Expect.equals( - world.invalidate!.length, filteredInvalidated?.length ?? 0); + world.invalidate!.length, + filteredInvalidated?.length ?? 0, + "Unexpected invalidated files: ${filteredInvalidated}, " + "actual: ${world.invalidate}."); if (world.expectedInvalidatedUri != null) { Expect.setEquals( world.expectedInvalidatedUri!.map((s) => base.resolve(s)), diff --git a/pkg/front_end/testcases/incremental/flutter_widget_factory.yaml b/pkg/front_end/testcases/incremental/flutter_widget_factory.yaml new file mode 100644 index 00000000000..c5a72f92bba --- /dev/null +++ b/pkg/front_end/testcases/incremental/flutter_widget_factory.yaml @@ -0,0 +1,144 @@ +# Copyright (c) 2022, 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.md file. + +type: newworld +target: dartdevc +trackWidgetCreation: true +worlds: + - entry: main.dart + sources: + main.dart: | + import 'foo.dart'; + Foo newFoo = new Foo(); + var newFooFunction = Foo.new; + var newFooFunctionCall = newFooFunction(); + Foo extensionFoo = null.foo(); + var extensionFooFunction = null.foo; + var extensionFooFunctionCall = extensionFooFunction(); + Foo extensionBar = null.bar(); + Foo extensionBaz = null.baz(); + Foo extensionBoz = null.boz(); + Foo extensionConstFoo = null.constFoo(); + Foo extensionGetterFoo = null.getterFoo; + var extensionSetterFoo = () => null.setterFoo = null; + Foo extensionOperatorFoo = -null; + Foo extensionStaticFoo = FooExtension.staticFoo(); + foo.dart: | + import 'package:flutter/src/widgets/framework.dart'; + + const alias = widgetFactory; + const nullableAlias = false ? widgetFactory : null; + const nonNullableAlias = false ? widgetFactory : alias; + + class Foo extends Widget { + factory Foo() => const Foo._(); + + const Foo._(); + } + + extension FooExtension on Object? { + @widgetFactory + Foo foo() => Foo._(); + + @alias + Foo bar() => Foo._(); + + @nullableAlias + Foo baz() => Foo._(); + + @nonNullableAlias + Foo boz() => Foo._(); + + @widgetFactory + Foo constFoo() => const Foo._(); + + @widgetFactory + Foo get getterFoo => new Foo._(); + + @widgetFactory + void set setterFoo(_) => new Foo._(); + + @widgetFactory + Foo operator -() => new Foo._(); + + @widgetFactory + static Foo staticFoo() => new Foo._(); + } + flutter/lib/src/widgets/framework.dart: | + export 'widget_inspector.dart' show widgetFactory; + + abstract class Bar { + const Bar(); + } + abstract class Widget extends Bar { + const Widget(); + } + flutter/lib/src/widgets/widget_inspector.dart: | + abstract class _HasCreationLocation { + _Location get _location; + } + /// A tuple with file, line, and column number, for displaying human-readable + /// file locations. + class _Location { + const _Location({ + required this.file, + required this.line, + required this.column, + required this.name, + required this.parameterLocations, + }); + /// File path of the location. + final String file; + /// 1-based line number. + final int line; + /// 1-based column number. + final int column; + /// Optional name of the parameter or function at this location. + final String name; + /// Optional locations of the parameters of the member at this location. + final List<_Location> parameterLocations; + } + + class _WidgetFactory { + const _WidgetFactory(); + } + + const widgetFactory = _WidgetFactory(); + .dart_tool/package_config.json: | + { + "configVersion": 2, + "packages": [ + { + "name": "flutter", + "rootUri": "../flutter", + "packageUri": "lib/" + } + ] + } + expectedLibraryCount: 4 + + - entry: main.dart + worldType: updated + invalidate: + - main.dart + expectInitializeFromDill: false + sources: + main.dart: | + import 'foo.dart'; + Foo extensionConstFoo = null.constFoo(); + Foo newFoo = new Foo(); + var newFooFunction = Foo.new; + var newFooFunctionCall = newFooFunction(); + Foo extensionFoo = null.foo(); + var extensionFooFunction = null.foo; + var extensionFooFunctionCall = extensionFooFunction(); + Foo extensionBar = null.bar(); + Foo extensionBaz = null.baz(); + Foo extensionBoz = null.boz(); + Foo extensionGetterFoo = null.getterFoo; + var extensionSetterFoo = () => null.setterFoo = null; + Foo extensionOperatorFoo = -null; + Foo extensionStaticFoo = FooExtension.staticFoo(); + expectedLibraryCount: 4 + advancedInvalidation: bodiesOnly diff --git a/pkg/front_end/testcases/incremental/flutter_widget_factory.yaml.world.1.expect b/pkg/front_end/testcases/incremental/flutter_widget_factory.yaml.world.1.expect new file mode 100644 index 00000000000..0f30faab532 --- /dev/null +++ b/pkg/front_end/testcases/incremental/flutter_widget_factory.yaml.world.1.expect @@ -0,0 +1,215 @@ +main = ; +library from "package:flutter/src/widgets/framework.dart" as fra { +additionalExports = (wid::widgetFactory) + + export "package:flutter/src/widgets/widget_inspector.dart" show widgetFactory; + + abstract class Bar extends dart.core::Object /*hasConstConstructor*/ { + const constructor •() → fra::Bar + : super dart.core::Object::•() + ; + } + abstract class Widget extends fra::Bar implements wid::_HasCreationLocation /*hasConstConstructor*/ { + final field wid::_Location? _location /*isLegacy*/; + const constructor •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → fra::Widget + : super fra::Bar::•(), fra::Widget::_location = $creationLocationd_0dea112b090073317d4 + ; + } +} +library from "package:flutter/src/widgets/widget_inspector.dart" as wid { + + abstract class _HasCreationLocation extends dart.core::Object { + synthetic constructor •() → wid::_HasCreationLocation + : super dart.core::Object::•() + ; + abstract get _location() → wid::_Location; + } + class _Location extends dart.core::Object /*hasConstConstructor*/ { + final field dart.core::String file; + final field dart.core::int line; + final field dart.core::int column; + final field dart.core::String name; + final field dart.core::List parameterLocations; + const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List parameterLocations = #C1}) → wid::_Location + : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•() + ; + static method _#new#tearOff({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List parameterLocations = #C1}) → wid::_Location + return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations); + } + class _WidgetFactory extends dart.core::Object /*hasConstConstructor*/ { + const constructor •() → wid::_WidgetFactory + : super dart.core::Object::•() + ; + static method _#new#tearOff() → wid::_WidgetFactory + return new wid::_WidgetFactory::•(); + } + static const field wid::_WidgetFactory widgetFactory = #C2; +} +library from "org-dartlang-test:///foo.dart" as foo { + + import "package:flutter/src/widgets/framework.dart"; + + class Foo extends fra::Widget /*hasConstConstructor*/ { + const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4) + ; + static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return #C8; + static method _#new#tearOff() → foo::Foo + return foo::Foo::•($creationLocationd_0dea112b090073317d4: #C10); + static method _#_#tearOff() → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C13); + } + extension FooExtension on dart.core::Object? { + method foo = foo::FooExtension|foo; + tearoff foo = foo::FooExtension|get#foo; + method bar = foo::FooExtension|bar; + tearoff bar = foo::FooExtension|get#bar; + method baz = foo::FooExtension|baz; + tearoff baz = foo::FooExtension|get#baz; + method boz = foo::FooExtension|boz; + tearoff boz = foo::FooExtension|get#boz; + method constFoo = foo::FooExtension|constFoo; + tearoff constFoo = foo::FooExtension|get#constFoo; + get getterFoo = foo::FooExtension|get#getterFoo; + operator unary- = foo::FooExtension|unary-; + static method staticFoo = foo::FooExtension|staticFoo; + set setterFoo = foo::FooExtension|set#setterFoo; + } + static const field wid::_WidgetFactory alias = #C2; + static const field wid::_WidgetFactory? nullableAlias = #C1; + static const field wid::_WidgetFactory nonNullableAlias = #C2; + @#C2 + static method FooExtension|foo(lowered final dart.core::Object? #this, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#foo(lowered final dart.core::Object? #this) → () → foo::Foo + return () → foo::Foo => foo::FooExtension|foo(#this, $creationLocationd_0dea112b090073317d4: #C17); + @#C2 + static method FooExtension|bar(lowered final dart.core::Object? #this, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#bar(lowered final dart.core::Object? #this) → () → foo::Foo + return () → foo::Foo => foo::FooExtension|bar(#this, $creationLocationd_0dea112b090073317d4: #C20); + @#C1 + static method FooExtension|baz(lowered final dart.core::Object? #this) → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C23); + static method FooExtension|get#baz(lowered final dart.core::Object? #this) → () → foo::Foo + return () → foo::Foo => foo::FooExtension|baz(#this); + @#C2 + static method FooExtension|boz(lowered final dart.core::Object? #this, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#boz(lowered final dart.core::Object? #this) → () → foo::Foo + return () → foo::Foo => foo::FooExtension|boz(#this, $creationLocationd_0dea112b090073317d4: #C26); + @#C2 + static method FooExtension|constFoo(lowered final dart.core::Object? #this, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return #C29; + static method FooExtension|get#constFoo(lowered final dart.core::Object? #this) → () → foo::Foo + return () → foo::Foo => foo::FooExtension|constFoo(#this, $creationLocationd_0dea112b090073317d4: #C31); + @#C2 + static method FooExtension|get#getterFoo(lowered final dart.core::Object? #this, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + @#C2 + static method FooExtension|set#setterFoo(lowered final dart.core::Object? #this, dynamic _, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → void + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + @#C2 + static method FooExtension|unary-(lowered final dart.core::Object? #this, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + @#C2 + static method FooExtension|staticFoo() → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C34); +} +library from "org-dartlang-test:///main.dart" as main { + + import "org-dartlang-test:///foo.dart"; + + static field foo::Foo newFoo = foo::Foo::•($creationLocationd_0dea112b090073317d4: #C37); + static field () → foo::Foo newFooFunction = #C38; + static field foo::Foo newFooFunctionCall = main::newFooFunction(){() → foo::Foo}; + static field foo::Foo extensionFoo = foo::FooExtension|foo(null, $creationLocationd_0dea112b090073317d4: #C41); + static field () → foo::Foo extensionFooFunction = foo::FooExtension|get#foo(null); + static field foo::Foo extensionFooFunctionCall = main::extensionFooFunction(){() → foo::Foo}; + static field foo::Foo extensionBar = foo::FooExtension|bar(null, $creationLocationd_0dea112b090073317d4: #C42); + static field foo::Foo extensionBaz = foo::FooExtension|baz(null); + static field foo::Foo extensionBoz = foo::FooExtension|boz(null, $creationLocationd_0dea112b090073317d4: #C43); + static field foo::Foo extensionConstFoo = foo::FooExtension|constFoo(null, $creationLocationd_0dea112b090073317d4: #C45); + static field foo::Foo extensionGetterFoo = foo::FooExtension|get#getterFoo(null, $creationLocationd_0dea112b090073317d4: #C49); + static field () → Null extensionSetterFoo = () → Null => let final has-declared-initializer Null #t1 = null in let final void #t2 = foo::FooExtension|set#setterFoo(null, #t1, $creationLocationd_0dea112b090073317d4: #C53) in #t1; + static field foo::Foo extensionOperatorFoo = foo::FooExtension|unary-(null, $creationLocationd_0dea112b090073317d4: #C57); + static field foo::Foo extensionStaticFoo = foo::FooExtension|staticFoo(); +} +constants { + #C1 = null + #C2 = wid::_WidgetFactory {} + #C3 = "org-dartlang-test:///foo.dart" + #C4 = 8.0 + #C5 = 26.0 + #C6 = "Foo" + #C7 = wid::_Location {file:#C3, line:#C4, column:#C5, name:#C6, parameterLocations:#C1} + #C8 = foo::Foo {_location:#C7} + #C9 = 11.0 + #C10 = wid::_Location {file:#C3, line:#C4, column:#C9, name:#C6, parameterLocations:#C1} + #C11 = 10.0 + #C12 = 9.0 + #C13 = wid::_Location {file:#C3, line:#C11, column:#C12, name:#C6, parameterLocations:#C1} + #C14 = 15.0 + #C15 = 7.0 + #C16 = "FooExtension|foo" + #C17 = wid::_Location {file:#C3, line:#C14, column:#C15, name:#C16, parameterLocations:#C1} + #C18 = 18.0 + #C19 = "FooExtension|bar" + #C20 = wid::_Location {file:#C3, line:#C18, column:#C15, name:#C19, parameterLocations:#C1} + #C21 = 21.0 + #C22 = 20.0 + #C23 = wid::_Location {file:#C3, line:#C21, column:#C22, name:#C6, parameterLocations:#C1} + #C24 = 24.0 + #C25 = "FooExtension|boz" + #C26 = wid::_Location {file:#C3, line:#C24, column:#C15, name:#C25, parameterLocations:#C1} + #C27 = 27.0 + #C28 = wid::_Location {file:#C3, line:#C27, column:#C27, name:#C6, parameterLocations:#C1} + #C29 = foo::Foo {_location:#C28} + #C30 = "FooExtension|constFoo" + #C31 = wid::_Location {file:#C3, line:#C27, column:#C15, name:#C30, parameterLocations:#C1} + #C32 = 39.0 + #C33 = 33.0 + #C34 = wid::_Location {file:#C3, line:#C32, column:#C33, name:#C6, parameterLocations:#C1} + #C35 = "org-dartlang-test:///main.dart" + #C36 = 2.0 + #C37 = wid::_Location {file:#C35, line:#C36, column:#C18, name:#C6, parameterLocations:#C1} + #C38 = static-tearoff foo::Foo::_#new#tearOff + #C39 = 5.0 + #C40 = 25.0 + #C41 = wid::_Location {file:#C35, line:#C39, column:#C40, name:#C16, parameterLocations:#C1} + #C42 = wid::_Location {file:#C35, line:#C4, column:#C40, name:#C19, parameterLocations:#C1} + #C43 = wid::_Location {file:#C35, line:#C11, column:#C40, name:#C25, parameterLocations:#C1} + #C44 = 30.0 + #C45 = wid::_Location {file:#C35, line:#C9, column:#C44, name:#C30, parameterLocations:#C1} + #C46 = 12.0 + #C47 = 31.0 + #C48 = "FooExtension|get#getterFoo" + #C49 = wid::_Location {file:#C35, line:#C46, column:#C47, name:#C48, parameterLocations:#C1} + #C50 = 13.0 + #C51 = 37.0 + #C52 = "FooExtension|set#setterFoo" + #C53 = wid::_Location {file:#C35, line:#C50, column:#C51, name:#C52, parameterLocations:#C1} + #C54 = 14.0 + #C55 = 28.0 + #C56 = "FooExtension|unary-" + #C57 = wid::_Location {file:#C35, line:#C54, column:#C55, name:#C56, parameterLocations:#C1} +} + + +Constructor coverage from constants: +org-dartlang-test:///main.dart: +- _Location. (from org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart:7:9) +- Object. (from org-dartlang-sdk:///lib/core/object.dart) + +org-dartlang-test:///foo.dart: +- _Location. (from org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart:7:9) +- Object. (from org-dartlang-sdk:///lib/core/object.dart) +- Foo._ (from org-dartlang-test:///foo.dart:10:9) +- Widget. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:7:9) +- Bar. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:4:9) + +org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart: +- _WidgetFactory. (from org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart:27:9) +- Object. (from org-dartlang-sdk:///lib/core/object.dart) + diff --git a/pkg/front_end/testcases/incremental/flutter_widget_factory.yaml.world.2.expect b/pkg/front_end/testcases/incremental/flutter_widget_factory.yaml.world.2.expect new file mode 100644 index 00000000000..77e8b035636 --- /dev/null +++ b/pkg/front_end/testcases/incremental/flutter_widget_factory.yaml.world.2.expect @@ -0,0 +1,216 @@ +main = ; +library from "package:flutter/src/widgets/framework.dart" as fra { +additionalExports = (wid::widgetFactory) + + export "package:flutter/src/widgets/widget_inspector.dart" show widgetFactory; + + abstract class Bar extends dart.core::Object /*hasConstConstructor*/ { + const constructor •() → fra::Bar + : super dart.core::Object::•() + ; + } + abstract class Widget extends fra::Bar implements wid::_HasCreationLocation /*hasConstConstructor*/ { + final field wid::_Location? _location /*isLegacy*/; + const constructor •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → fra::Widget + : super fra::Bar::•(), fra::Widget::_location = $creationLocationd_0dea112b090073317d4 + ; + } +} +library from "package:flutter/src/widgets/widget_inspector.dart" as wid { + + abstract class _HasCreationLocation extends dart.core::Object { + synthetic constructor •() → wid::_HasCreationLocation + : super dart.core::Object::•() + ; + abstract get _location() → wid::_Location; + } + class _Location extends dart.core::Object /*hasConstConstructor*/ { + final field dart.core::String file; + final field dart.core::int line; + final field dart.core::int column; + final field dart.core::String name; + final field dart.core::List parameterLocations; + const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List parameterLocations = #C1}) → wid::_Location + : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•() + ; + static method _#new#tearOff({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List parameterLocations = #C1}) → wid::_Location + return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations); + } + class _WidgetFactory extends dart.core::Object /*hasConstConstructor*/ { + const constructor •() → wid::_WidgetFactory + : super dart.core::Object::•() + ; + static method _#new#tearOff() → wid::_WidgetFactory + return new wid::_WidgetFactory::•(); + } + static const field wid::_WidgetFactory widgetFactory = #C2; +} +library from "org-dartlang-test:///foo.dart" as foo { + + import "package:flutter/src/widgets/framework.dart"; + + class Foo extends fra::Widget /*hasConstConstructor*/ { + const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4) + ; + static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return #C8; + static method _#new#tearOff() → foo::Foo + return foo::Foo::•($creationLocationd_0dea112b090073317d4: #C10); + static method _#_#tearOff() → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C13); + } + extension FooExtension on dart.core::Object? { + method foo = foo::FooExtension|foo; + tearoff foo = foo::FooExtension|get#foo; + method bar = foo::FooExtension|bar; + tearoff bar = foo::FooExtension|get#bar; + method baz = foo::FooExtension|baz; + tearoff baz = foo::FooExtension|get#baz; + method boz = foo::FooExtension|boz; + tearoff boz = foo::FooExtension|get#boz; + method constFoo = foo::FooExtension|constFoo; + tearoff constFoo = foo::FooExtension|get#constFoo; + get getterFoo = foo::FooExtension|get#getterFoo; + operator unary- = foo::FooExtension|unary-; + static method staticFoo = foo::FooExtension|staticFoo; + set setterFoo = foo::FooExtension|set#setterFoo; + } + static const field wid::_WidgetFactory alias = #C2; + static const field wid::_WidgetFactory? nullableAlias = #C1; + static const field wid::_WidgetFactory nonNullableAlias = #C2; + @#C2 + static method FooExtension|foo(lowered final dart.core::Object? #this, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#foo(lowered final dart.core::Object? #this) → () → foo::Foo + return () → foo::Foo => foo::FooExtension|foo(#this, $creationLocationd_0dea112b090073317d4: #C17); + @#C2 + static method FooExtension|bar(lowered final dart.core::Object? #this, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#bar(lowered final dart.core::Object? #this) → () → foo::Foo + return () → foo::Foo => foo::FooExtension|bar(#this, $creationLocationd_0dea112b090073317d4: #C20); + @#C1 + static method FooExtension|baz(lowered final dart.core::Object? #this) → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C23); + static method FooExtension|get#baz(lowered final dart.core::Object? #this) → () → foo::Foo + return () → foo::Foo => foo::FooExtension|baz(#this); + @#C2 + static method FooExtension|boz(lowered final dart.core::Object? #this, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#boz(lowered final dart.core::Object? #this) → () → foo::Foo + return () → foo::Foo => foo::FooExtension|boz(#this, $creationLocationd_0dea112b090073317d4: #C26); + @#C2 + static method FooExtension|constFoo(lowered final dart.core::Object? #this, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return #C29; + static method FooExtension|get#constFoo(lowered final dart.core::Object? #this) → () → foo::Foo + return () → foo::Foo => foo::FooExtension|constFoo(#this, $creationLocationd_0dea112b090073317d4: #C31); + @#C2 + static method FooExtension|get#getterFoo(lowered final dart.core::Object? #this, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + @#C2 + static method FooExtension|set#setterFoo(lowered final dart.core::Object? #this, dynamic _, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → void + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + @#C2 + static method FooExtension|unary-(lowered final dart.core::Object? #this, {wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + @#C2 + static method FooExtension|staticFoo() → foo::Foo + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C34); +} +library from "org-dartlang-test:///main.dart" as main { + + import "org-dartlang-test:///foo.dart"; + + static field foo::Foo extensionConstFoo = foo::FooExtension|constFoo(null, $creationLocationd_0dea112b090073317d4: #C38); + static field foo::Foo newFoo = foo::Foo::•($creationLocationd_0dea112b090073317d4: #C40); + static field () → foo::Foo newFooFunction = #C41; + static field foo::Foo newFooFunctionCall = main::newFooFunction(){() → foo::Foo}; + static field foo::Foo extensionFoo = foo::FooExtension|foo(null, $creationLocationd_0dea112b090073317d4: #C44); + static field ({$creationLocationd_0dea112b090073317d4: wid::_Location?}) → foo::Foo extensionFooFunction = foo::FooExtension|get#foo(null); + static field foo::Foo extensionFooFunctionCall = main::extensionFooFunction(){({$creationLocationd_0dea112b090073317d4: wid::_Location?}) → foo::Foo}; + static field foo::Foo extensionBar = foo::FooExtension|bar(null, $creationLocationd_0dea112b090073317d4: #C45); + static field foo::Foo extensionBaz = foo::FooExtension|baz(null); + static field foo::Foo extensionBoz = foo::FooExtension|boz(null, $creationLocationd_0dea112b090073317d4: #C46); + static field foo::Foo extensionGetterFoo = foo::FooExtension|get#getterFoo(null, $creationLocationd_0dea112b090073317d4: #C50); + static field () → Null extensionSetterFoo = () → Null => let final has-declared-initializer Null #t1 = null in let final void #t2 = foo::FooExtension|set#setterFoo(null, #t1, $creationLocationd_0dea112b090073317d4: #C54) in #t1; + static field foo::Foo extensionOperatorFoo = foo::FooExtension|unary-(null, $creationLocationd_0dea112b090073317d4: #C58); + static field foo::Foo extensionStaticFoo = foo::FooExtension|staticFoo(); +} +constants { + #C1 = null + #C2 = wid::_WidgetFactory {} + #C3 = "org-dartlang-test:///foo.dart" + #C4 = 8.0 + #C5 = 26.0 + #C6 = "Foo" + #C7 = wid::_Location {file:#C3, line:#C4, column:#C5, name:#C6, parameterLocations:#C1} + #C8 = foo::Foo {_location:#C7} + #C9 = 11.0 + #C10 = wid::_Location {file:#C3, line:#C4, column:#C9, name:#C6, parameterLocations:#C1} + #C11 = 10.0 + #C12 = 9.0 + #C13 = wid::_Location {file:#C3, line:#C11, column:#C12, name:#C6, parameterLocations:#C1} + #C14 = 15.0 + #C15 = 7.0 + #C16 = "FooExtension|foo" + #C17 = wid::_Location {file:#C3, line:#C14, column:#C15, name:#C16, parameterLocations:#C1} + #C18 = 18.0 + #C19 = "FooExtension|bar" + #C20 = wid::_Location {file:#C3, line:#C18, column:#C15, name:#C19, parameterLocations:#C1} + #C21 = 21.0 + #C22 = 20.0 + #C23 = wid::_Location {file:#C3, line:#C21, column:#C22, name:#C6, parameterLocations:#C1} + #C24 = 24.0 + #C25 = "FooExtension|boz" + #C26 = wid::_Location {file:#C3, line:#C24, column:#C15, name:#C25, parameterLocations:#C1} + #C27 = 27.0 + #C28 = wid::_Location {file:#C3, line:#C27, column:#C27, name:#C6, parameterLocations:#C1} + #C29 = foo::Foo {_location:#C28} + #C30 = "FooExtension|constFoo" + #C31 = wid::_Location {file:#C3, line:#C27, column:#C15, name:#C30, parameterLocations:#C1} + #C32 = 39.0 + #C33 = 33.0 + #C34 = wid::_Location {file:#C3, line:#C32, column:#C33, name:#C6, parameterLocations:#C1} + #C35 = "org-dartlang-test:///main.dart" + #C36 = 2.0 + #C37 = 30.0 + #C38 = wid::_Location {file:#C35, line:#C36, column:#C37, name:#C30, parameterLocations:#C1} + #C39 = 3.0 + #C40 = wid::_Location {file:#C35, line:#C39, column:#C18, name:#C6, parameterLocations:#C1} + #C41 = static-tearoff foo::Foo::_#new#tearOff + #C42 = 6.0 + #C43 = 25.0 + #C44 = wid::_Location {file:#C35, line:#C42, column:#C43, name:#C16, parameterLocations:#C1} + #C45 = wid::_Location {file:#C35, line:#C12, column:#C43, name:#C19, parameterLocations:#C1} + #C46 = wid::_Location {file:#C35, line:#C9, column:#C43, name:#C25, parameterLocations:#C1} + #C47 = 12.0 + #C48 = 31.0 + #C49 = "FooExtension|get#getterFoo" + #C50 = wid::_Location {file:#C35, line:#C47, column:#C48, name:#C49, parameterLocations:#C1} + #C51 = 13.0 + #C52 = 37.0 + #C53 = "FooExtension|set#setterFoo" + #C54 = wid::_Location {file:#C35, line:#C51, column:#C52, name:#C53, parameterLocations:#C1} + #C55 = 14.0 + #C56 = 28.0 + #C57 = "FooExtension|unary-" + #C58 = wid::_Location {file:#C35, line:#C55, column:#C56, name:#C57, parameterLocations:#C1} +} + + +Constructor coverage from constants: +org-dartlang-test:///foo.dart: +- _Location. (from org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart:7:9) +- Object. (from org-dartlang-sdk:///lib/core/object.dart) +- Foo._ (from org-dartlang-test:///foo.dart:10:9) +- Widget. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:7:9) +- Bar. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:4:9) + +org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart: +- _WidgetFactory. (from org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart:27:9) +- Object. (from org-dartlang-sdk:///lib/core/object.dart) + +org-dartlang-test:///main.dart: +- _Location. (from org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart:7:9) +- Object. (from org-dartlang-sdk:///lib/core/object.dart) + diff --git a/pkg/front_end/testcases/incremental/flutter_widget_factory_legacy.yaml b/pkg/front_end/testcases/incremental/flutter_widget_factory_legacy.yaml new file mode 100644 index 00000000000..1f79d1d707c --- /dev/null +++ b/pkg/front_end/testcases/incremental/flutter_widget_factory_legacy.yaml @@ -0,0 +1,125 @@ +# Copyright (c) 2022, 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.md file. + +type: newworld +target: dartdevc +trackWidgetCreation: true +worlds: + - entry: main.dart + sources: + main.dart: | + import 'foo.dart'; + Foo newFoo = new Foo(); + var newFooFunction = Foo.new; + var newFooFunctionCall = newFooFunction(); + Foo extensionFoo = null.foo(); + var extensionFooFunction = null.foo; + var extensionFooFunctionCall = extensionFooFunction(); + Foo extensionBar = null.bar(); + Foo extensionBaz = null.baz(); + Foo extensionBoz = null.boz(); + Foo extensionConstFoo = null.constFoo(); + foo.dart: | + // @dart=2.9 + import 'package:flutter/src/widgets/framework.dart'; + + const alias = widgetFactory; + const nullableAlias = false ? widgetFactory : null; + const nonNullableAlias = false ? widgetFactory : alias; + + class Foo extends Widget { + factory Foo() => const Foo._(); + + const Foo._(); + } + + extension FooExtension on Object { + @widgetFactory + Foo foo() => Foo._(); + + @alias + Foo bar() => Foo._(); + + @nullableAlias + Foo baz() => Foo._(); + + @nonNullableAlias + Foo boz() => Foo._(); + + @widgetFactory + Foo constFoo() => const Foo._(); + } + flutter/lib/src/widgets/framework.dart: | + export 'widget_inspector.dart' show widgetFactory; + + abstract class Bar { + const Bar(); + } + abstract class Widget extends Bar { + const Widget(); + } + flutter/lib/src/widgets/widget_inspector.dart: | + abstract class _HasCreationLocation { + _Location get _location; + } + /// A tuple with file, line, and column number, for displaying human-readable + /// file locations. + class _Location { + const _Location({ + required this.file, + required this.line, + required this.column, + required this.name, + required this.parameterLocations, + }); + /// File path of the location. + final String file; + /// 1-based line number. + final int line; + /// 1-based column number. + final int column; + /// Optional name of the parameter or function at this location. + final String name; + /// Optional locations of the parameters of the member at this location. + final List<_Location> parameterLocations; + } + + class _WidgetFactory { + const _WidgetFactory(); + } + + const widgetFactory = _WidgetFactory(); + .dart_tool/package_config.json: | + { + "configVersion": 2, + "packages": [ + { + "name": "flutter", + "rootUri": "../flutter", + "packageUri": "lib/" + } + ] + } + expectedLibraryCount: 4 + + - entry: main.dart + worldType: updated + invalidate: + - main.dart + expectInitializeFromDill: false + sources: + main.dart: | + import 'foo.dart'; + Foo extensionConstFoo = null.constFoo(); + Foo newFoo = new Foo(); + var newFooFunction = Foo.new; + var newFooFunctionCall = newFooFunction(); + Foo extensionFoo = null.foo(); + var extensionFooFunction = null.foo; + var extensionFooFunctionCall = extensionFooFunction(); + Foo extensionBar = null.bar(); + Foo extensionBaz = null.baz(); + Foo extensionBoz = null.boz(); + expectedLibraryCount: 4 + advancedInvalidation: bodiesOnly diff --git a/pkg/front_end/testcases/incremental/flutter_widget_factory_legacy.yaml.world.1.expect b/pkg/front_end/testcases/incremental/flutter_widget_factory_legacy.yaml.world.1.expect new file mode 100644 index 00000000000..b99d086bc15 --- /dev/null +++ b/pkg/front_end/testcases/incremental/flutter_widget_factory_legacy.yaml.world.1.expect @@ -0,0 +1,187 @@ +main = ; +library from "package:flutter/src/widgets/framework.dart" as fra { +additionalExports = (wid::widgetFactory) + + export "package:flutter/src/widgets/widget_inspector.dart" show widgetFactory; + + abstract class Bar extends dart.core::Object /*hasConstConstructor*/ { + const constructor •() → fra::Bar + : super dart.core::Object::•() + ; + } + abstract class Widget extends fra::Bar implements wid::_HasCreationLocation /*hasConstConstructor*/ { + final field wid::_Location? _location /*isLegacy*/; + const constructor •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → fra::Widget + : super fra::Bar::•(), fra::Widget::_location = $creationLocationd_0dea112b090073317d4 + ; + } +} +library from "package:flutter/src/widgets/widget_inspector.dart" as wid { + + abstract class _HasCreationLocation extends dart.core::Object { + synthetic constructor •() → wid::_HasCreationLocation + : super dart.core::Object::•() + ; + abstract get _location() → wid::_Location; + } + class _Location extends dart.core::Object /*hasConstConstructor*/ { + final field dart.core::String file; + final field dart.core::int line; + final field dart.core::int column; + final field dart.core::String name; + final field dart.core::List parameterLocations; + const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List parameterLocations = #C1}) → wid::_Location + : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•() + ; + static method _#new#tearOff({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List parameterLocations = #C1}) → wid::_Location + return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations); + } + class _WidgetFactory extends dart.core::Object /*hasConstConstructor*/ { + const constructor •() → wid::_WidgetFactory + : super dart.core::Object::•() + ; + static method _#new#tearOff() → wid::_WidgetFactory + return new wid::_WidgetFactory::•(); + } + static const field wid::_WidgetFactory widgetFactory = #C2; +} +library from "org-dartlang-test:///foo.dart" as foo { + + import "package:flutter/src/widgets/framework.dart"; + + class Foo extends fra::Widget /*hasConstConstructor*/ { + const constructor _({wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4) + ; + static factory •({wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + return #C8; + static method _#new#tearOff() → foo::Foo* + return foo::Foo::•($creationLocationd_0dea112b090073317d4: #C10); + static method _#_#tearOff() → foo::Foo* + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C11); + abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod + abstract member-signature operator ==(dynamic other) → dart.core::bool*; -> dart.core::Object::== + abstract member-signature get hashCode() → dart.core::int*; -> dart.core::Object::hashCode + abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString + abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType + } + extension FooExtension on dart.core::Object* { + method foo = foo::FooExtension|foo; + tearoff foo = foo::FooExtension|get#foo; + method bar = foo::FooExtension|bar; + tearoff bar = foo::FooExtension|get#bar; + method baz = foo::FooExtension|baz; + tearoff baz = foo::FooExtension|get#baz; + method boz = foo::FooExtension|boz; + tearoff boz = foo::FooExtension|get#boz; + method constFoo = foo::FooExtension|constFoo; + tearoff constFoo = foo::FooExtension|get#constFoo; + } + static const field wid::_WidgetFactory* alias = #C2; + static const field wid::_WidgetFactory* nullableAlias = #C1; + static const field wid::_WidgetFactory* nonNullableAlias = #C2; + @#C2 + static method FooExtension|foo(lowered final dart.core::Object* #this, {wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#foo(lowered final dart.core::Object* #this) → () →* foo::Foo* + return () → foo::Foo* => foo::FooExtension|foo(#this, $creationLocationd_0dea112b090073317d4: #C15); + @#C2 + static method FooExtension|bar(lowered final dart.core::Object* #this, {wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#bar(lowered final dart.core::Object* #this) → () →* foo::Foo* + return () → foo::Foo* => foo::FooExtension|bar(#this, $creationLocationd_0dea112b090073317d4: #C18); + @#C1 + static method FooExtension|baz(lowered final dart.core::Object* #this, {wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#baz(lowered final dart.core::Object* #this) → () →* foo::Foo* + return () → foo::Foo* => foo::FooExtension|baz(#this, $creationLocationd_0dea112b090073317d4: #C21); + @#C2 + static method FooExtension|boz(lowered final dart.core::Object* #this, {wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#boz(lowered final dart.core::Object* #this) → () →* foo::Foo* + return () → foo::Foo* => foo::FooExtension|boz(#this, $creationLocationd_0dea112b090073317d4: #C24); + @#C2 + static method FooExtension|constFoo(lowered final dart.core::Object* #this, {wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + return #C28; + static method FooExtension|get#constFoo(lowered final dart.core::Object* #this) → () →* foo::Foo* + return () → foo::Foo* => foo::FooExtension|constFoo(#this, $creationLocationd_0dea112b090073317d4: #C30); +} +library from "org-dartlang-test:///main.dart" as main { + + import "org-dartlang-test:///foo.dart"; + + static field foo::Foo newFoo = foo::Foo::•($creationLocationd_0dea112b090073317d4: #C34); + static field () → foo::Foo newFooFunction = #C35; + static field foo::Foo newFooFunctionCall = main::newFooFunction(){() → foo::Foo}; + static field foo::Foo extensionFoo = foo::FooExtension|foo(null, $creationLocationd_0dea112b090073317d4: #C37); + static field () → foo::Foo extensionFooFunction = foo::FooExtension|get#foo(null); + static field foo::Foo extensionFooFunctionCall = main::extensionFooFunction(){() → foo::Foo}; + static field foo::Foo extensionBar = foo::FooExtension|bar(null, $creationLocationd_0dea112b090073317d4: #C39); + static field foo::Foo extensionBaz = foo::FooExtension|baz(null, $creationLocationd_0dea112b090073317d4: #C40); + static field foo::Foo extensionBoz = foo::FooExtension|boz(null, $creationLocationd_0dea112b090073317d4: #C42); + static field foo::Foo extensionConstFoo = foo::FooExtension|constFoo(null, $creationLocationd_0dea112b090073317d4: #C44); +} +constants { + #C1 = null + #C2 = wid::_WidgetFactory {} + #C3 = "org-dartlang-test:///foo.dart" + #C4 = 9.0 + #C5 = 26.0 + #C6 = "Foo" + #C7 = wid::_Location {file:#C3, line:#C4, column:#C5, name:#C6, parameterLocations:#C1} + #C8 = foo::Foo {_location:#C7} + #C9 = 11.0 + #C10 = wid::_Location {file:#C3, line:#C4, column:#C9, name:#C6, parameterLocations:#C1} + #C11 = wid::_Location {file:#C3, line:#C9, column:#C4, name:#C6, parameterLocations:#C1} + #C12 = 16.0 + #C13 = 7.0 + #C14 = "FooExtension|foo" + #C15 = wid::_Location {file:#C3, line:#C12, column:#C13, name:#C14, parameterLocations:#C1} + #C16 = 19.0 + #C17 = "FooExtension|bar" + #C18 = wid::_Location {file:#C3, line:#C16, column:#C13, name:#C17, parameterLocations:#C1} + #C19 = 22.0 + #C20 = "FooExtension|baz" + #C21 = wid::_Location {file:#C3, line:#C19, column:#C13, name:#C20, parameterLocations:#C1} + #C22 = 25.0 + #C23 = "FooExtension|boz" + #C24 = wid::_Location {file:#C3, line:#C22, column:#C13, name:#C23, parameterLocations:#C1} + #C25 = 28.0 + #C26 = 27.0 + #C27 = wid::_Location {file:#C3, line:#C25, column:#C26, name:#C6, parameterLocations:#C1} + #C28 = foo::Foo {_location:#C27} + #C29 = "FooExtension|constFoo" + #C30 = wid::_Location {file:#C3, line:#C25, column:#C13, name:#C29, parameterLocations:#C1} + #C31 = "org-dartlang-test:///main.dart" + #C32 = 2.0 + #C33 = 18.0 + #C34 = wid::_Location {file:#C31, line:#C32, column:#C33, name:#C6, parameterLocations:#C1} + #C35 = static-tearoff foo::Foo::_#new#tearOff + #C36 = 5.0 + #C37 = wid::_Location {file:#C31, line:#C36, column:#C22, name:#C14, parameterLocations:#C1} + #C38 = 8.0 + #C39 = wid::_Location {file:#C31, line:#C38, column:#C22, name:#C17, parameterLocations:#C1} + #C40 = wid::_Location {file:#C31, line:#C4, column:#C22, name:#C20, parameterLocations:#C1} + #C41 = 10.0 + #C42 = wid::_Location {file:#C31, line:#C41, column:#C22, name:#C23, parameterLocations:#C1} + #C43 = 30.0 + #C44 = wid::_Location {file:#C31, line:#C9, column:#C43, name:#C29, parameterLocations:#C1} +} + + +Constructor coverage from constants: +org-dartlang-test:///main.dart: +- _Location. (from org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart:7:9) +- Object. (from org-dartlang-sdk:///lib/core/object.dart) + +org-dartlang-test:///foo.dart: +- _Location. (from org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart:7:9) +- Object. (from org-dartlang-sdk:///lib/core/object.dart) +- Foo._ (from org-dartlang-test:///foo.dart:11:9) +- Widget. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:7:9) +- Bar. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:4:9) + +org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart: +- _WidgetFactory. (from org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart:27:9) +- Object. (from org-dartlang-sdk:///lib/core/object.dart) + diff --git a/pkg/front_end/testcases/incremental/flutter_widget_factory_legacy.yaml.world.2.expect b/pkg/front_end/testcases/incremental/flutter_widget_factory_legacy.yaml.world.2.expect new file mode 100644 index 00000000000..b722a36a32b --- /dev/null +++ b/pkg/front_end/testcases/incremental/flutter_widget_factory_legacy.yaml.world.2.expect @@ -0,0 +1,187 @@ +main = ; +library from "package:flutter/src/widgets/framework.dart" as fra { +additionalExports = (wid::widgetFactory) + + export "package:flutter/src/widgets/widget_inspector.dart" show widgetFactory; + + abstract class Bar extends dart.core::Object /*hasConstConstructor*/ { + const constructor •() → fra::Bar + : super dart.core::Object::•() + ; + } + abstract class Widget extends fra::Bar implements wid::_HasCreationLocation /*hasConstConstructor*/ { + final field wid::_Location? _location /*isLegacy*/; + const constructor •({wid::_Location? $creationLocationd_0dea112b090073317d4 = #C1}) → fra::Widget + : super fra::Bar::•(), fra::Widget::_location = $creationLocationd_0dea112b090073317d4 + ; + } +} +library from "package:flutter/src/widgets/widget_inspector.dart" as wid { + + abstract class _HasCreationLocation extends dart.core::Object { + synthetic constructor •() → wid::_HasCreationLocation + : super dart.core::Object::•() + ; + abstract get _location() → wid::_Location; + } + class _Location extends dart.core::Object /*hasConstConstructor*/ { + final field dart.core::String file; + final field dart.core::int line; + final field dart.core::int column; + final field dart.core::String name; + final field dart.core::List parameterLocations; + const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List parameterLocations = #C1}) → wid::_Location + : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•() + ; + static method _#new#tearOff({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List parameterLocations = #C1}) → wid::_Location + return new wid::_Location::•(file: file, line: line, column: column, name: name, parameterLocations: parameterLocations); + } + class _WidgetFactory extends dart.core::Object /*hasConstConstructor*/ { + const constructor •() → wid::_WidgetFactory + : super dart.core::Object::•() + ; + static method _#new#tearOff() → wid::_WidgetFactory + return new wid::_WidgetFactory::•(); + } + static const field wid::_WidgetFactory widgetFactory = #C2; +} +library from "org-dartlang-test:///foo.dart" as foo { + + import "package:flutter/src/widgets/framework.dart"; + + class Foo extends fra::Widget /*hasConstConstructor*/ { + const constructor _({wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4) + ; + static factory •({wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + return #C8; + static method _#new#tearOff() → foo::Foo* + return foo::Foo::•($creationLocationd_0dea112b090073317d4: #C10); + static method _#_#tearOff() → foo::Foo* + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C11); + abstract member-signature method noSuchMethod(dart.core::Invocation* invocation) → dynamic; -> dart.core::Object::noSuchMethod + abstract member-signature operator ==(dynamic other) → dart.core::bool*; -> dart.core::Object::== + abstract member-signature get hashCode() → dart.core::int*; -> dart.core::Object::hashCode + abstract member-signature method toString() → dart.core::String*; -> dart.core::Object::toString + abstract member-signature get runtimeType() → dart.core::Type*; -> dart.core::Object::runtimeType + } + extension FooExtension on dart.core::Object* { + method foo = foo::FooExtension|foo; + tearoff foo = foo::FooExtension|get#foo; + method bar = foo::FooExtension|bar; + tearoff bar = foo::FooExtension|get#bar; + method baz = foo::FooExtension|baz; + tearoff baz = foo::FooExtension|get#baz; + method boz = foo::FooExtension|boz; + tearoff boz = foo::FooExtension|get#boz; + method constFoo = foo::FooExtension|constFoo; + tearoff constFoo = foo::FooExtension|get#constFoo; + } + static const field wid::_WidgetFactory* alias = #C2; + static const field wid::_WidgetFactory* nullableAlias = #C1; + static const field wid::_WidgetFactory* nonNullableAlias = #C2; + @#C2 + static method FooExtension|foo(lowered final dart.core::Object* #this, {wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#foo(lowered final dart.core::Object* #this) → () →* foo::Foo* + return () → foo::Foo* => foo::FooExtension|foo(#this, $creationLocationd_0dea112b090073317d4: #C15); + @#C2 + static method FooExtension|bar(lowered final dart.core::Object* #this, {wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#bar(lowered final dart.core::Object* #this) → () →* foo::Foo* + return () → foo::Foo* => foo::FooExtension|bar(#this, $creationLocationd_0dea112b090073317d4: #C18); + @#C1 + static method FooExtension|baz(lowered final dart.core::Object* #this, {wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#baz(lowered final dart.core::Object* #this) → () →* foo::Foo* + return () → foo::Foo* => foo::FooExtension|baz(#this, $creationLocationd_0dea112b090073317d4: #C21); + @#C2 + static method FooExtension|boz(lowered final dart.core::Object* #this, {wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + return new foo::Foo::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4); + static method FooExtension|get#boz(lowered final dart.core::Object* #this) → () →* foo::Foo* + return () → foo::Foo* => foo::FooExtension|boz(#this, $creationLocationd_0dea112b090073317d4: #C24); + @#C2 + static method FooExtension|constFoo(lowered final dart.core::Object* #this, {wid::_Location* $creationLocationd_0dea112b090073317d4 = #C1}) → foo::Foo* + return #C28; + static method FooExtension|get#constFoo(lowered final dart.core::Object* #this) → () →* foo::Foo* + return () → foo::Foo* => foo::FooExtension|constFoo(#this, $creationLocationd_0dea112b090073317d4: #C30); +} +library from "org-dartlang-test:///main.dart" as main { + + import "org-dartlang-test:///foo.dart"; + + static field foo::Foo extensionConstFoo = foo::FooExtension|constFoo(null, $creationLocationd_0dea112b090073317d4: #C34); + static field foo::Foo newFoo = foo::Foo::•($creationLocationd_0dea112b090073317d4: #C37); + static field () → foo::Foo newFooFunction = #C38; + static field foo::Foo newFooFunctionCall = main::newFooFunction(){() → foo::Foo}; + static field foo::Foo extensionFoo = foo::FooExtension|foo(null, $creationLocationd_0dea112b090073317d4: #C40); + static field ({$creationLocationd_0dea112b090073317d4: wid::_Location}) → foo::Foo extensionFooFunction = foo::FooExtension|get#foo(null); + static field foo::Foo extensionFooFunctionCall = main::extensionFooFunction(){({$creationLocationd_0dea112b090073317d4: wid::_Location}) → foo::Foo}; + static field foo::Foo extensionBar = foo::FooExtension|bar(null, $creationLocationd_0dea112b090073317d4: #C41); + static field foo::Foo extensionBaz = foo::FooExtension|baz(null, $creationLocationd_0dea112b090073317d4: #C43); + static field foo::Foo extensionBoz = foo::FooExtension|boz(null, $creationLocationd_0dea112b090073317d4: #C44); +} +constants { + #C1 = null + #C2 = wid::_WidgetFactory {} + #C3 = "org-dartlang-test:///foo.dart" + #C4 = 9.0 + #C5 = 26.0 + #C6 = "Foo" + #C7 = wid::_Location {file:#C3, line:#C4, column:#C5, name:#C6, parameterLocations:#C1} + #C8 = foo::Foo {_location:#C7} + #C9 = 11.0 + #C10 = wid::_Location {file:#C3, line:#C4, column:#C9, name:#C6, parameterLocations:#C1} + #C11 = wid::_Location {file:#C3, line:#C9, column:#C4, name:#C6, parameterLocations:#C1} + #C12 = 16.0 + #C13 = 7.0 + #C14 = "FooExtension|foo" + #C15 = wid::_Location {file:#C3, line:#C12, column:#C13, name:#C14, parameterLocations:#C1} + #C16 = 19.0 + #C17 = "FooExtension|bar" + #C18 = wid::_Location {file:#C3, line:#C16, column:#C13, name:#C17, parameterLocations:#C1} + #C19 = 22.0 + #C20 = "FooExtension|baz" + #C21 = wid::_Location {file:#C3, line:#C19, column:#C13, name:#C20, parameterLocations:#C1} + #C22 = 25.0 + #C23 = "FooExtension|boz" + #C24 = wid::_Location {file:#C3, line:#C22, column:#C13, name:#C23, parameterLocations:#C1} + #C25 = 28.0 + #C26 = 27.0 + #C27 = wid::_Location {file:#C3, line:#C25, column:#C26, name:#C6, parameterLocations:#C1} + #C28 = foo::Foo {_location:#C27} + #C29 = "FooExtension|constFoo" + #C30 = wid::_Location {file:#C3, line:#C25, column:#C13, name:#C29, parameterLocations:#C1} + #C31 = "org-dartlang-test:///main.dart" + #C32 = 2.0 + #C33 = 30.0 + #C34 = wid::_Location {file:#C31, line:#C32, column:#C33, name:#C29, parameterLocations:#C1} + #C35 = 3.0 + #C36 = 18.0 + #C37 = wid::_Location {file:#C31, line:#C35, column:#C36, name:#C6, parameterLocations:#C1} + #C38 = static-tearoff foo::Foo::_#new#tearOff + #C39 = 6.0 + #C40 = wid::_Location {file:#C31, line:#C39, column:#C22, name:#C14, parameterLocations:#C1} + #C41 = wid::_Location {file:#C31, line:#C4, column:#C22, name:#C17, parameterLocations:#C1} + #C42 = 10.0 + #C43 = wid::_Location {file:#C31, line:#C42, column:#C22, name:#C20, parameterLocations:#C1} + #C44 = wid::_Location {file:#C31, line:#C9, column:#C22, name:#C23, parameterLocations:#C1} +} + + +Constructor coverage from constants: +org-dartlang-test:///foo.dart: +- _Location. (from org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart:7:9) +- Object. (from org-dartlang-sdk:///lib/core/object.dart) +- Foo._ (from org-dartlang-test:///foo.dart:11:9) +- Widget. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:7:9) +- Bar. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:4:9) + +org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart: +- _WidgetFactory. (from org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart:27:9) +- Object. (from org-dartlang-sdk:///lib/core/object.dart) + +org-dartlang-test:///main.dart: +- _Location. (from org-dartlang-test:///flutter/lib/src/widgets/widget_inspector.dart:7:9) +- Object. (from org-dartlang-sdk:///lib/core/object.dart) + diff --git a/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart b/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart index 736060b81f6..ab65caf3538 100644 --- a/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart +++ b/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart @@ -103,22 +103,37 @@ bool _maybeAddNamedParameter( return true; } -/// Transformer that modifies all calls to Widget constructors to include -/// a [DebugLocation] parameter specifying the location where the constructor -/// call was made. +/// Transformer that modifies all calls to Widget constructors and "Widget +/// factories" to include a _Location parameter specifying the location where +/// the constructor or widget factory call was made. /// -/// This transformer requires that all Widget constructors have already been -/// transformed to have a named parameter with the name specified by -/// `_locationParameterName`. +/// This transformer requires that all Widget constructors and Widget factories +/// have already been transformed to have a named parameter with the name +/// specified by `_locationParameterName`. +/// +/// A "Widget factory" is an extension instance method annotated with the +/// `@widgetFactory` annotations. A _Location parameter is added to such methods +/// and this is used as the location value for all Widget constructor +/// invocations within the method. class _WidgetCallSiteTransformer extends Transformer { /// The [Widget] class defined in the `package:flutter` library. /// - /// Used to perform instanceof checks to determine whether Dart constructor - /// calls are creating [Widget] objects. - Class _widgetClass; + /// Used to perform is-tests to determine whether Dart constructor calls are + /// creating [Widget] objects. + final Class _widgetClass; - /// The [DebugLocation] class defined in the `package:flutter` library. - Class _locationClass; + /// The _Location class defined in the `package:flutter` library. + final Class _locationClass; + + final WidgetCreatorTracker _tracker; + + /// The creation location parameter of the extension factory method enclosing + /// the node that is currently being transformed. + /// + /// Used to flow the creation location parameter to the call sites of widget + /// constructors and extension factory methods within an enclosing extension + /// factory method. + Expression? _currentExtensionFactoryLocationParameter; /// Current factory constructor that node being transformed is inside. /// @@ -126,23 +141,21 @@ class _WidgetCallSiteTransformer extends Transformer { /// actual constructor call within the factory. Procedure? _currentFactory; - WidgetCreatorTracker _tracker; - /// Library that contains the transformed call sites. /// /// The transformation of the call sites is affected by the NNBD opt-in status /// of the library. Library? _currentLibrary; - _WidgetCallSiteTransformer( - {required Class widgetClass, - required Class locationClass, - required WidgetCreatorTracker tracker}) - : _widgetClass = widgetClass, + _WidgetCallSiteTransformer({ + required Class widgetClass, + required Class locationClass, + required WidgetCreatorTracker tracker, + }) : _widgetClass = widgetClass, _locationClass = locationClass, _tracker = tracker; - /// Builds a call to the const constructor of the [DebugLocation] + /// Builds a call to the const constructor of the _Location /// object specifying the location where a constructor call was made and /// optionally the locations for all parameters passed in. /// @@ -172,6 +185,17 @@ class _WidgetCallSiteTransformer extends Transformer { @override Procedure visitProcedure(Procedure node) { + if (_isWidgetFactory(node)) { + final VariableDeclaration locationParameter = + node.function.namedParameters.firstWhere( + (parameter) => parameter.name == _creationLocationParameterName, + ); + _currentExtensionFactoryLocationParameter = + VariableGet(locationParameter); + node.transformChildren(this); + _currentExtensionFactoryLocationParameter = null; + return node; + } if (node.isFactory) { _currentFactory = node; node.transformChildren(this); @@ -186,30 +210,55 @@ class _WidgetCallSiteTransformer extends Transformer { return _tracker._isSubclassOf(clazz, _widgetClass); } + bool _isWidgetFactory(Procedure node) { + return node.isExtensionMember && + _hasNamedParameter(node.function, _creationLocationParameterName); + } + @override StaticInvocation visitStaticInvocation(StaticInvocation node) { node.transformChildren(this); final Procedure target = node.target; - if (!target.isFactory) { - return node; - } - final Class constructedClass = target.enclosingClass!; - if (!_isSubclassOfWidget(constructedClass)) { - return node; - } + if (target.isFactory) { + final Class constructedClass = target.enclosingClass!; + if (!_isSubclassOfWidget(constructedClass)) { + return node; + } - _addLocationArgument(node, target.function, constructedClass, - isConst: node.isConst); + _addLocationArgument( + node, + target.function, + constructedClass: constructedClass, + isConst: node.isConst, + ); + return node; + } + if (_isWidgetFactory(target)) { + _addLocationArgument(node, target.function); + return node; + } return node; } void _addLocationArgument( - InvocationExpression node, FunctionNode function, Class constructedClass, - {bool isConst = false}) { + InvocationExpression node, + FunctionNode function, { + Class? constructedClass, + bool isConst = false, + }) { + Expression? location = _currentExtensionFactoryLocationParameter; + if (location == null || + // We cannot pass the location parameter of the enclosing extension + // factory method to a const constructor call, so we fallback to + // passing the location of the constructor call. + isConst) { + location = + _computeLocation(node, function, constructedClass, isConst: isConst); + } _maybeAddCreationLocationArgument( node.arguments, function, - _computeLocation(node, function, constructedClass, isConst: isConst), + location, _locationClass, ); } @@ -224,20 +273,27 @@ class _WidgetCallSiteTransformer extends Transformer { return node; } - _addLocationArgument(node, constructor.function, constructedClass, - isConst: node.isConst); + _addLocationArgument( + node, + constructor.function, + constructedClass: constructedClass, + isConst: node.isConst, + ); return node; } Expression _computeLocation( InvocationExpression node, FunctionNode function, - Class constructedClass, { + Class? constructedClass, { bool isConst = false, }) { + assert(constructedClass != null || !isConst); + // For factory constructors we need to use the location specified as an // argument to the factory constructor rather than the location - if (_currentFactory != null && + if (constructedClass != null && + _currentFactory != null && _tracker._isSubclassOf( constructedClass, _currentFactory!.enclosingClass!) && // If the constructor invocation is constant we cannot refer to the @@ -255,7 +311,9 @@ class _WidgetCallSiteTransformer extends Transformer { return _constructLocation( node.location!, - name: constructedClass.name, + name: constructedClass?.name ?? + // For extension factory methods we use the name of the method. + (function.parent! as Procedure).name.text, ); } @@ -274,12 +332,18 @@ class _WidgetCallSiteTransformer extends Transformer { } } -/// Rewrites all widget constructors and constructor invocations to add a -/// parameter specifying the location the constructor was called from. +/// Rewrites all Widget constructors, constructor invocations, +/// "Widget factories", and Widget factory invocations to add a +/// parameter specifying the location the constructor/factory was called from. /// /// The creation location is stored as a private field named `_location` -/// on the base widget class and flowed through the constructors using a named +/// on the base Widget class and flowed through the constructors using a named /// parameter. +/// +/// A "Widget factory" is an extension instance method annotated with the +/// `@widgetFactory` annotations. A _Location parameter is added to such methods +/// and this is used as the location value for all Widget constructor +/// invocations within the method. class WidgetCreatorTracker { bool _foundClasses = false; late Class _widgetClass; @@ -289,6 +353,13 @@ class WidgetCreatorTracker { /// available. late Class _hasCreationLocationClass; + /// Annotation class used to mark an extension method as a "Widget factory". + /// + /// Widgets created within the body of an extension factory method will have + /// their creation location set to the call site of the extension factory + /// method. + Class? _widgetFactoryClass; + void _resolveFlutterClasses(Iterable libraries) { // If the Widget or Debug location classes have been updated we need to get // the latest version @@ -315,12 +386,16 @@ class WidgetCreatorTracker { } else if (class_.name == '_Location') { _locationClass = class_; foundLocationClass = true; + } else if (class_.name == '_WidgetFactory') { + _widgetFactoryClass = class_; } } } } } } + // TODO(johnniwinther): Require the [_widgetFactoryClass] once the + // `widgetFactory` is stably in flutter. _foundClasses = foundWidgetClass && foundHasCreationLocationClass && foundLocationClass; } @@ -427,7 +502,8 @@ class WidgetCreatorTracker { /// Transform the given [libraries]. /// /// The libraries from [module] is searched for the Widget class, - /// the _Location class and the _HasCreationLocation class. + /// the _Location class, the _HasCreationLocation class and the + /// _WidgetFactory class. /// If the component does not contain them, the ones from a previous run is /// used (if any), otherwise no transformation is performed. /// @@ -450,6 +526,7 @@ class WidgetCreatorTracker { } final Set transformedClasses = new Set.identity(); + final Set transformedExtensions = new Set.identity(); final Set librariesToTransform = new Set.identity() ..addAll(libraries); @@ -462,14 +539,24 @@ class WidgetCreatorTracker { changedStructureNotifier, ); } + if (_widgetFactoryClass != null) { + for (Extension extension in library.extensions) { + _transformWidgetFactories( + librariesToTransform, + transformedExtensions, + extension, + ); + } + } } // Transform call sites to pass the location parameter. final _WidgetCallSiteTransformer callsiteTransformer = new _WidgetCallSiteTransformer( - widgetClass: _widgetClass, - locationClass: _locationClass, - tracker: this); + widgetClass: _widgetClass, + locationClass: _locationClass, + tracker: this, + ); for (Library library in libraries) { callsiteTransformer.enterLibrary(library); @@ -491,6 +578,32 @@ class WidgetCreatorTracker { return false; } + bool _hasWidgetFactoryAnnotation(Procedure node) => + _isAnnotatedWithNamedValueOfType(node, _widgetFactoryClass!); + + bool _isAnnotatedWithNamedValueOfType( + Annotatable node, + Class annotationClass, + ) { + return node.annotations.any((annotation) { + if (annotation is! StaticGet) { + return false; + } + final Member target = annotation.target; + if (target is! Field) { + return false; + } + final DartType type = target.type; + if (type is! InterfaceType) { + return false; + } + if (type.nullability == Nullability.nullable) { + return false; + } + return type.classNode == _widgetFactoryClass; + }); + } + void _transformWidgetConstructors( Set librariesToBeTransformed, Set transformedClasses, @@ -583,4 +696,41 @@ class WidgetCreatorTracker { clazz.constructors.forEach(handleConstructor); } + + void _transformWidgetFactories( + Set librariesToBeTransformed, + Set transformedExtensions, + Extension extension, + ) { + // TODO(johnniwinther): We should have a lint for unsupported use of + // `@widgetFactory`. + assert(_widgetFactoryClass != null); + + if (!librariesToBeTransformed.contains(extension.enclosingLibrary) || + !transformedExtensions.add(extension)) { + return; + } + + for (ExtensionMemberDescriptor member in extension.members) { + if (member.isStatic) { + // We could support static extension methods but it is not clear that + // there is a use case for this. + continue; + } + final Procedure method = member.member.asProcedure; + if (_hasWidgetFactoryAnnotation(method)) { + _maybeAddNamedParameter( + method.function, + new VariableDeclaration( + _creationLocationParameterName, + type: new InterfaceType( + _locationClass, + extension.enclosingLibrary.nullable, + ), + initializer: new NullLiteral(), + ), + ); + } + } + } }