[CFE] Widget tracking for extension method widget factories

This CL extends the widget tracking frontend kernel transformer to
support tracking the callsites of extension methods that act as widget
factories as the creation location of widgets.

To enable this support extension methods have to be annotated.

Fixes https://github.com/dart-lang/sdk/issues/50067

Originally created by gabriel@terwesten.net in
https://dart-review.googlesource.com/c/sdk/+/263380

Change-Id: I6efe8f081263e58659b9c6374542ad8f04361136
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/275901
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Johnni Winther 2022-12-19 09:13:04 +00:00 committed by Commit Queue
parent cebaa403c1
commit fe3f2188ff
8 changed files with 1271 additions and 44 deletions

View file

@ -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)),

View file

@ -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

View file

@ -0,0 +1,215 @@
main = <No Member>;
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<wid::_Location> 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<wid::_Location> 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<wid::_Location> 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)

View file

@ -0,0 +1,216 @@
main = <No Member>;
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<wid::_Location> 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<wid::_Location> 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<wid::_Location> 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)

View file

@ -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

View file

@ -0,0 +1,187 @@
main = <No Member>;
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<wid::_Location> 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<wid::_Location> 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<wid::_Location> 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)

View file

@ -0,0 +1,187 @@
main = <No Member>;
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<wid::_Location> 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<wid::_Location> 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<wid::_Location> 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)

View file

@ -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<Library> 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<Class> transformedClasses = new Set<Class>.identity();
final Set<Extension> transformedExtensions = new Set<Extension>.identity();
final Set<Library> librariesToTransform = new Set<Library>.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<Library> librariesToBeTransformed,
Set<Class> transformedClasses,
@ -583,4 +696,41 @@ class WidgetCreatorTracker {
clazz.constructors.forEach(handleConstructor);
}
void _transformWidgetFactories(
Set<Library> librariesToBeTransformed,
Set<Extension> 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(),
),
);
}
}
}
}