Add annotation-based creation location tracking
Closes https://github.com/dart-lang/sdk/pull/63011 GitOrigin-RevId: 926534c2f5d3cd1e9629cf25f6b028ab34c00e64 Change-Id: I88460a060faabeae8f611e88f23b2eb5fc99f21a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/491702 Reviewed-by: Daco Harkes <dacoharkes@google.com> Reviewed-by: Jens Johansen <jensj@google.com> Reviewed-by: Slava Egorov <vegorov@google.com> Commit-Queue: Daco Harkes <dacoharkes@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
efff5f70c1
commit
9e8fdef17c
@@ -109,9 +109,16 @@ final ArgParser _argParser = ArgParser(allowTrailingOptions: true)
|
||||
help: 'Print this help message.',
|
||||
)
|
||||
..addFlag(
|
||||
'track-widget-creation',
|
||||
help: 'Run a kernel transformer to track creation locations for widgets.',
|
||||
'track-creation-locations',
|
||||
help:
|
||||
'Run a kernel transformer to track creation locations for'
|
||||
' classes annotated with @pragma(\'track-creation-locations\').',
|
||||
defaultsTo: false,
|
||||
aliases: [
|
||||
// TODO(http://dartbug.com/63225): Remove this once flutter is migrated
|
||||
// to the new flag.
|
||||
'track-widget-creation',
|
||||
],
|
||||
)
|
||||
..addOption(
|
||||
'invocation-modes',
|
||||
@@ -186,7 +193,7 @@ Future<int> runCompilerWithCommandLineArguments(List<String> arguments) async {
|
||||
final String? validateDynamicInterface = options['validate'];
|
||||
final String messageVerbosity = options['verbosity'];
|
||||
final String cfeInvocationModes = options['invocation-modes'];
|
||||
final bool trackWidgetCreation = options['track-widget-creation'];
|
||||
final bool trackCreationLocations = options['track-creation-locations'];
|
||||
final List<String>? bytecodeGeneratorOptions = options['bytecode-options'];
|
||||
final String libraryUrisPrefix = options['prefix-library-uris']!;
|
||||
|
||||
@@ -205,7 +212,7 @@ Future<int> runCompilerWithCommandLineArguments(List<String> arguments) async {
|
||||
fileSystemRoots: fileSystemRoots,
|
||||
messageVerbosity: messageVerbosity,
|
||||
cfeInvocationModes: cfeInvocationModes,
|
||||
trackWidgetCreation: trackWidgetCreation,
|
||||
trackCreationLocations: trackCreationLocations,
|
||||
bytecodeGeneratorOptions: bytecodeGeneratorOptions,
|
||||
depfile: depfile,
|
||||
depfileTarget: depfileTarget,
|
||||
@@ -231,7 +238,7 @@ Future<int> runCompilerWithOptions({
|
||||
String messageVerbosity = Verbosity.defaultValue,
|
||||
void Function(String) printMessage = print,
|
||||
String cfeInvocationModes = '',
|
||||
bool trackWidgetCreation = false,
|
||||
bool trackCreationLocations = false,
|
||||
List<String>? bytecodeGeneratorOptions,
|
||||
String? depfile,
|
||||
String? depfileTarget,
|
||||
@@ -287,7 +294,7 @@ Future<int> runCompilerWithOptions({
|
||||
..verbosity = verbosity
|
||||
..target = createFrontEndTarget(
|
||||
targetName,
|
||||
trackWidgetCreation: trackWidgetCreation,
|
||||
trackCreationLocations: trackCreationLocations,
|
||||
supportMirrors: false,
|
||||
isClosureContextLoweringEnabled:
|
||||
bytecodeOptions.isClosureContextLoweringEnabled,
|
||||
|
||||
@@ -270,7 +270,7 @@ Future<CompilerResult> _compile(
|
||||
onWarning: print,
|
||||
);
|
||||
|
||||
var trackWidgetCreation = argResults.flag('track-widget-creation');
|
||||
var trackCreationLocations = argResults.flag('track-creation-locations');
|
||||
var oldCompilerState = compilerState;
|
||||
var recordUsedInputs = argResults.option('used-inputs-file') != null;
|
||||
var additionalDills = summaryModules.keys.toList();
|
||||
@@ -290,7 +290,9 @@ Future<CompilerResult> _compile(
|
||||
packageFile != null ? sourcePathToUri(packageFile) : null,
|
||||
sourcePathToUri(librarySpecPath),
|
||||
additionalDills,
|
||||
DevCompilerTarget(TargetFlags(trackWidgetCreation: trackWidgetCreation)),
|
||||
DevCompilerTarget(
|
||||
TargetFlags(trackCreationLocations: trackCreationLocations),
|
||||
),
|
||||
fileSystem: fileSystem,
|
||||
explicitExperimentalFlags: explicitExperimentalFlags,
|
||||
environmentDefines: declaredVariables,
|
||||
@@ -318,7 +320,7 @@ Future<CompilerResult> _compile(
|
||||
compilerState = await fe.initializeIncrementalCompiler(
|
||||
oldCompilerState,
|
||||
{
|
||||
'trackWidgetCreation=$trackWidgetCreation',
|
||||
'trackCreationLocations=$trackCreationLocations',
|
||||
'multiRootScheme=${fileSystem.markerScheme}',
|
||||
'multiRootRoots=${fileSystem.roots}',
|
||||
},
|
||||
@@ -330,7 +332,9 @@ Future<CompilerResult> _compile(
|
||||
sourcePathToUri(librarySpecPath),
|
||||
additionalDills,
|
||||
inputDigests,
|
||||
DevCompilerTarget(TargetFlags(trackWidgetCreation: trackWidgetCreation)),
|
||||
DevCompilerTarget(
|
||||
TargetFlags(trackCreationLocations: trackCreationLocations),
|
||||
),
|
||||
fileSystem: fileSystem,
|
||||
explicitExperimentalFlags: explicitExperimentalFlags,
|
||||
environmentDefines: declaredVariables,
|
||||
|
||||
@@ -368,10 +368,17 @@ class Options {
|
||||
hide: true,
|
||||
)
|
||||
..addFlag(
|
||||
'track-widget-creation',
|
||||
help: 'Enable inspecting of Flutter widgets.',
|
||||
'track-creation-locations',
|
||||
help:
|
||||
'Run a kernel transformer to track creation locations for'
|
||||
' classes annotated with @pragma(\'track-creation-locations\').',
|
||||
defaultsTo: false,
|
||||
hide: true,
|
||||
aliases: [
|
||||
// TODO(http://dartbug.com/63225): Remove this once flutter is
|
||||
// migrated to the new flag.
|
||||
'track-widget-creation',
|
||||
],
|
||||
)
|
||||
// TODO(jmesserly): add verbose help to show hidden options
|
||||
..addOption(
|
||||
|
||||
@@ -201,7 +201,7 @@ class ExpressionCompilerWorker {
|
||||
environmentDefines: environmentDefines,
|
||||
explicitExperimentalFlags: explicitExperimentalFlags,
|
||||
sdkRoot: _argToUri(parsedArgs.option('sdk-root')),
|
||||
trackWidgetCreation: parsedArgs.flag('track-widget-creation'),
|
||||
trackCreationLocations: parsedArgs.flag('track-creation-locations'),
|
||||
moduleFormat: moduleFormat,
|
||||
canaryFeatures: parsedArgs.flag('canary'),
|
||||
enableAsserts: parsedArgs.flag('enable-asserts'),
|
||||
@@ -227,7 +227,7 @@ class ExpressionCompilerWorker {
|
||||
Map<String, String>? environmentDefines,
|
||||
Map<ExperimentalFlag, bool> explicitExperimentalFlags = const {},
|
||||
Uri? sdkRoot,
|
||||
bool trackWidgetCreation = false,
|
||||
bool trackCreationLocations = false,
|
||||
ModuleFormat moduleFormat = ModuleFormat.amd,
|
||||
bool canaryFeatures = false,
|
||||
bool enableAsserts = true,
|
||||
@@ -244,7 +244,7 @@ class ExpressionCompilerWorker {
|
||||
..packagesFileUri = packagesFile
|
||||
..librariesSpecificationUri = librariesSpecificationUri
|
||||
..target = DevCompilerTarget(
|
||||
TargetFlags(trackWidgetCreation: trackWidgetCreation),
|
||||
TargetFlags(trackCreationLocations: trackCreationLocations),
|
||||
)
|
||||
..fileSystem = fileSystem
|
||||
..omitPlatform = true
|
||||
@@ -889,7 +889,15 @@ final argParser = ArgParser()
|
||||
..addOption('asset-server-address')
|
||||
..addOption('asset-server-port')
|
||||
..addOption('module-format', defaultsTo: 'amd')
|
||||
..addFlag('track-widget-creation', defaultsTo: false)
|
||||
..addFlag(
|
||||
'track-creation-locations',
|
||||
defaultsTo: false,
|
||||
aliases: [
|
||||
// TODO(http://dartbug.com/63225): Remove this once flutter is
|
||||
// migrated to the new flag.
|
||||
'track-widget-creation',
|
||||
],
|
||||
)
|
||||
..addFlag('sound-null-safety', negatable: true, defaultsTo: true)
|
||||
..addFlag('canary', negatable: true, defaultsTo: false)
|
||||
// Disable asserts in compiled code by default, which is different
|
||||
|
||||
@@ -240,6 +240,28 @@ class DevCompilerTarget extends Target {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void performOutlineTransformations(
|
||||
Component component, {
|
||||
List<Library>? libraries,
|
||||
ChangedStructureNotifier? changedStructureNotifier,
|
||||
}) {
|
||||
super.performOutlineTransformations(
|
||||
component,
|
||||
libraries: libraries,
|
||||
changedStructureNotifier: changedStructureNotifier,
|
||||
);
|
||||
// In addition to [performPreConstantEvaluationTransformations] this makes
|
||||
// sure summaries are also transformed.
|
||||
if (flags.trackCreationLocations) {
|
||||
(_widgetTracker ??= WidgetCreatorTracker()).transform(
|
||||
libraries ?? component.libraries,
|
||||
component.libraries,
|
||||
changedStructureNotifier,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void performPreConstantEvaluationTransformations(
|
||||
Component component,
|
||||
@@ -249,9 +271,12 @@ class DevCompilerTarget extends Target {
|
||||
void Function(String msg)? logger,
|
||||
ChangedStructureNotifier? changedStructureNotifier,
|
||||
}) {
|
||||
if (flags.trackWidgetCreation) {
|
||||
_widgetTracker ??= WidgetCreatorTracker();
|
||||
_widgetTracker!.transform(component, libraries, changedStructureNotifier);
|
||||
if (flags.trackCreationLocations) {
|
||||
(_widgetTracker ??= WidgetCreatorTracker()).transform(
|
||||
libraries,
|
||||
component.libraries,
|
||||
changedStructureNotifier,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ Future<MemoryComponentResult> componentFromMemory(
|
||||
null,
|
||||
sourcePathToUri(defaultLibrarySpecPath),
|
||||
[],
|
||||
DevCompilerTarget(TargetFlags(trackWidgetCreation: false)),
|
||||
DevCompilerTarget(TargetFlags(trackCreationLocations: false)),
|
||||
fileSystem: fe.HybridFileSystem(memoryFileSystem),
|
||||
environmentDefines: {},
|
||||
explicitExperimentalFlags: explicitExperimentalFlags,
|
||||
@@ -134,7 +134,7 @@ Future<MemoryComponentResult> incrementalComponentFromMemory(
|
||||
sourcePathToUri(defaultLibrarySpecPath),
|
||||
[],
|
||||
inputDigests,
|
||||
DevCompilerTarget(TargetFlags(trackWidgetCreation: false)),
|
||||
DevCompilerTarget(TargetFlags(trackCreationLocations: false)),
|
||||
fileSystem: fe.HybridFileSystem(memoryFileSystem),
|
||||
environmentDefines: {},
|
||||
explicitExperimentalFlags: explicitExperimentalFlags,
|
||||
|
||||
@@ -443,7 +443,12 @@ class IncrementalCompiler implements IncrementalKernelGenerator {
|
||||
}
|
||||
// Coverage-ignore(suite): Not run.
|
||||
else if (componentWithDill != null) {
|
||||
context.options.target.performOutlineTransformations(componentWithDill);
|
||||
context.options.target.performOutlineTransformations(
|
||||
componentWithDill,
|
||||
libraries: currentKernelTarget.loader.libraries,
|
||||
changedStructureNotifier:
|
||||
currentKernelTarget.changedStructureNotifier,
|
||||
);
|
||||
}
|
||||
|
||||
_benchmarker
|
||||
|
||||
@@ -190,14 +190,14 @@ Future<void> main(List<String> arguments) async {
|
||||
|
||||
CompilerContext setupCompilerContext(
|
||||
String targetString,
|
||||
bool widgetTransformation,
|
||||
bool trackCreationLocations,
|
||||
Uri platformUri,
|
||||
Uri mainUri,
|
||||
) {
|
||||
CompilerOptions options = getOptions();
|
||||
|
||||
TargetFlags targetFlags = new TargetFlags(
|
||||
trackWidgetCreation: widgetTransformation,
|
||||
trackCreationLocations: trackCreationLocations,
|
||||
);
|
||||
Target target;
|
||||
switch (targetString) {
|
||||
|
||||
@@ -56,8 +56,8 @@ Future<void> main(List<String> arguments) async {
|
||||
for (String s in arg.substring("--invalidate=".length).split(",")) {
|
||||
settings.invalidate.add(Uri.base.resolve(s));
|
||||
}
|
||||
} else if (arg.startsWith("--widgetTransformation")) {
|
||||
settings.widgetTransformation = true;
|
||||
} else if (arg.startsWith("--track-creation-locations")) {
|
||||
settings.trackCreationLocations = true;
|
||||
} else if (arg.startsWith("--target=vm")) {
|
||||
settings.targetString = "vm";
|
||||
} else if (arg.startsWith("--target=flutter")) {
|
||||
|
||||
@@ -68,7 +68,7 @@ class TestMinimizerSettings {
|
||||
bool invalidateAllAtOnce = false;
|
||||
bool experimentalInvalidation = false;
|
||||
bool serialize = false;
|
||||
bool widgetTransformation = false;
|
||||
bool trackCreationLocations = false;
|
||||
final List<Uri> invalidate = [];
|
||||
String targetString = "vm";
|
||||
bool noTryToDeleteEmptyFilesUpFront = false;
|
||||
@@ -103,7 +103,7 @@ class TestMinimizerSettings {
|
||||
'initialOnlyOutline': initialOnlyOutline,
|
||||
'experimentalInvalidation': experimentalInvalidation,
|
||||
'serialize': serialize,
|
||||
'widgetTransformation': widgetTransformation,
|
||||
'trackCreationLocations': trackCreationLocations,
|
||||
'invalidate': invalidate.map((uri) => uri.toString()).toList(),
|
||||
'targetString': targetString,
|
||||
'noTryToDeleteEmptyFilesUpFront': noTryToDeleteEmptyFilesUpFront,
|
||||
@@ -134,7 +134,7 @@ class TestMinimizerSettings {
|
||||
initialOnlyOutline = json["initialOnlyOutline"];
|
||||
experimentalInvalidation = json["experimentalInvalidation"];
|
||||
serialize = json["serialize"];
|
||||
widgetTransformation = json["widgetTransformation"];
|
||||
trackCreationLocations = json["trackCreationLocations"];
|
||||
invalidate.clear();
|
||||
invalidate.addAll(
|
||||
(json["invalidate"] as List).map((uriString) => Uri.parse(uriString)),
|
||||
@@ -802,8 +802,8 @@ class TestMinimizer {
|
||||
# Reproduce a crash.
|
||||
|
||||
type: newworld""");
|
||||
if (_settings.widgetTransformation) {
|
||||
print("trackWidgetCreation: true");
|
||||
if (_settings.trackCreationLocations) {
|
||||
print("trackCreationLocations: true");
|
||||
print("target: dartdevc # needed for widget creation to be run");
|
||||
}
|
||||
print("""
|
||||
@@ -2259,7 +2259,7 @@ worlds:
|
||||
}
|
||||
|
||||
TargetFlags targetFlags = new TargetFlags(
|
||||
trackWidgetCreation: _settings.widgetTransformation,
|
||||
trackCreationLocations: _settings.trackCreationLocations,
|
||||
);
|
||||
Target target;
|
||||
switch (_settings.targetString) {
|
||||
|
||||
@@ -279,7 +279,9 @@ bool isEqualBitForBit(List<int> a, List<int> b) {
|
||||
}
|
||||
|
||||
CompilerOptions getOptions(Uri sdkRoot) {
|
||||
Target target = new FlutterTarget(new TargetFlags(trackWidgetCreation: true));
|
||||
Target target = new FlutterTarget(
|
||||
new TargetFlags(trackCreationLocations: true),
|
||||
);
|
||||
CompilerOptions options = new CompilerOptions()
|
||||
..sdkRoot = sdkRoot
|
||||
..target = target
|
||||
|
||||
@@ -148,8 +148,8 @@ class NewWorldTestProperties {
|
||||
defaultValue: false,
|
||||
);
|
||||
|
||||
static const Property<bool> trackWidgetCreation = Property.optional(
|
||||
'trackWidgetCreation',
|
||||
static const Property<bool> trackCreationLocations = Property.optional(
|
||||
'trackCreationLocations',
|
||||
BoolValue(),
|
||||
defaultValue: false,
|
||||
);
|
||||
@@ -724,10 +724,8 @@ class RunCompilations extends Step<TestData, TestData, Context> {
|
||||
forceLateLoweringForTesting: NewWorldTestProperties
|
||||
.forceLateLoweringForTesting
|
||||
.read(map, keys),
|
||||
trackWidgetCreation: NewWorldTestProperties.trackWidgetCreation.read(
|
||||
map,
|
||||
keys,
|
||||
),
|
||||
trackCreationLocations: NewWorldTestProperties.trackCreationLocations
|
||||
.read(map, keys),
|
||||
incrementalSerialization: NewWorldTestProperties
|
||||
.incrementalSerialization
|
||||
.read(map, keys),
|
||||
@@ -1260,7 +1258,7 @@ class NewWorldTest {
|
||||
final Map<String, Map<String, String>>? modules;
|
||||
final bool omitPlatform;
|
||||
final bool forceLateLoweringForTesting;
|
||||
final bool trackWidgetCreation;
|
||||
final bool trackCreationLocations;
|
||||
final bool incrementalSerialization;
|
||||
final String? targetName;
|
||||
|
||||
@@ -1279,7 +1277,7 @@ class NewWorldTest {
|
||||
required this.modules,
|
||||
required this.omitPlatform,
|
||||
required this.forceLateLoweringForTesting,
|
||||
required this.trackWidgetCreation,
|
||||
required this.trackCreationLocations,
|
||||
required this.incrementalSerialization,
|
||||
required this.targetName,
|
||||
});
|
||||
@@ -1296,7 +1294,7 @@ class NewWorldTest {
|
||||
forceLateLoweringsForTesting: forceLateLoweringForTesting
|
||||
? LateLowering.all
|
||||
: null,
|
||||
trackWidgetCreation: trackWidgetCreation,
|
||||
trackCreationLocations: trackCreationLocations,
|
||||
);
|
||||
Target target = new VmTarget(targetFlags);
|
||||
if (targetName != null) {
|
||||
|
||||
@@ -83,7 +83,7 @@ Future<Component> processUri(
|
||||
Component? fullComponent,
|
||||
Uri packageUri,
|
||||
) async {
|
||||
TargetFlags targetFlags = new TargetFlags(trackWidgetCreation: false);
|
||||
TargetFlags targetFlags = new TargetFlags(trackCreationLocations: false);
|
||||
Target? target = new Dart2jsTarget("dart2js", targetFlags);
|
||||
Uri sdkSummary = Uri.base.resolve("out/ReleaseX64/dart2js_outline.dill");
|
||||
Stopwatch stopwatch = new Stopwatch()..start();
|
||||
|
||||
@@ -1452,6 +1452,7 @@ happen
|
||||
happened
|
||||
happens
|
||||
hard
|
||||
hardcoded
|
||||
hare
|
||||
has
|
||||
hash
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Reproduce a crash.
|
||||
|
||||
type: newworld
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
target: dartdevc # basically needed for widget creation to be run
|
||||
worlds:
|
||||
- entry: app/main.dart
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Reproduce a crash.
|
||||
|
||||
type: newworld
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
target: dartdevc # basically needed for widget creation to be run
|
||||
worlds:
|
||||
- entry: app/main.dart
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Reproduce a crash.
|
||||
|
||||
type: newworld
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
target: dartdevc # basically needed for widget creation to be run
|
||||
worlds:
|
||||
- entry: app/main.dart
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Reproduce a crash.
|
||||
|
||||
type: newworld
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
target: dartdevc # basically needed for widget creation to be run
|
||||
worlds:
|
||||
- entry: app/main.dart
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
skipClassHierarchyTest: true
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
sources:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
sources:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
sources:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
sources:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
sources:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
sources:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
sources:
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
# for details. All rights reserved. Use of this source code is governed by a
|
||||
# BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
sources:
|
||||
widget.dart: |
|
||||
@pragma('track-creation-locations')
|
||||
abstract class Widget {
|
||||
const Widget();
|
||||
}
|
||||
|
||||
class StandardWidget extends Widget {
|
||||
const StandardWidget();
|
||||
const StandardWidget.named(String name);
|
||||
}
|
||||
main.dart: |
|
||||
import 'widget.dart';
|
||||
|
||||
class MyWidget extends Widget {
|
||||
const MyWidget({this.child});
|
||||
|
||||
final Widget? child;
|
||||
}
|
||||
|
||||
void main() {
|
||||
var w1 = MyWidget();
|
||||
var w2 = StandardWidget.named('w2');
|
||||
const w3 = MyWidget();
|
||||
}
|
||||
expectedLibraryCount: 2
|
||||
|
||||
- entry: main.dart
|
||||
worldType: updated
|
||||
expectInitializeFromDill: false
|
||||
invalidate:
|
||||
- main.dart
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'widget.dart';
|
||||
|
||||
class MyWidget extends Widget {
|
||||
const MyWidget({this.child});
|
||||
|
||||
final Widget? child;
|
||||
}
|
||||
|
||||
void main() {
|
||||
var w1 = MyWidget(child: StandardWidget());
|
||||
const w2 = MyWidget(child: StandardWidget.named('w2'));
|
||||
const w3 = MyWidget(child: w2);
|
||||
}
|
||||
expectedLibraryCount: 2
|
||||
advancedInvalidation: bodiesOnly
|
||||
@@ -0,0 +1,80 @@
|
||||
main = main::main;
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///widget.dart";
|
||||
|
||||
class MyWidget extends wid::Widget /*hasConstConstructor*/ {
|
||||
final field wid::Widget? child;
|
||||
const constructor •({initializing-formal wid::Widget? child = #C1, dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C1}) → main::MyWidget
|
||||
: main::MyWidget::child = child, super wid::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static synthetic method _#new#tearOff({wid::Widget? child = #C1}) → main::MyWidget
|
||||
return new main::MyWidget::•(child: child, $creationLocationd_0dea112b090073317d4: #C6);
|
||||
}
|
||||
static method main() → void {
|
||||
main::MyWidget w1 = new main::MyWidget::•($creationLocationd_0dea112b090073317d4: #C9);
|
||||
wid::StandardWidget w2 = new wid::StandardWidget::named("w2", $creationLocationd_0dea112b090073317d4: #C13);
|
||||
const main::MyWidget w3 = #C16;
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///widget.dart" as wid {
|
||||
|
||||
@#C18
|
||||
abstract class Widget extends dart.core::Object implements dart.developer::_HasCreationLocation /*hasConstConstructor*/ {
|
||||
final field dart.developer::CreationLocation? dart.developer::_location;
|
||||
const constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C1}) → wid::Widget
|
||||
: super dart.core::Object::•(), wid::Widget::_location = $creationLocationd_0dea112b090073317d4
|
||||
;
|
||||
}
|
||||
class StandardWidget extends wid::Widget /*hasConstConstructor*/ {
|
||||
const constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C1}) → wid::StandardWidget
|
||||
: super wid::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
const constructor named(dart.core::String name, {dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C1}) → wid::StandardWidget
|
||||
: super wid::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static synthetic method _#new#tearOff() → wid::StandardWidget
|
||||
return new wid::StandardWidget::•($creationLocationd_0dea112b090073317d4: #C21);
|
||||
static synthetic method _#named#tearOff(dart.core::String name) → wid::StandardWidget
|
||||
return new wid::StandardWidget::named(name, $creationLocationd_0dea112b090073317d4: #C23);
|
||||
}
|
||||
}
|
||||
constants {
|
||||
#C1 = null
|
||||
#C2 = "org-dartlang-test:///main.dart"
|
||||
#C3 = 4.0
|
||||
#C4 = 9.0
|
||||
#C5 = "MyWidget"
|
||||
#C6 = dart.developer::CreationLocation {file:#C2, line:#C3, column:#C4, name:#C5}
|
||||
#C7 = 10.0
|
||||
#C8 = 12.0
|
||||
#C9 = dart.developer::CreationLocation {file:#C2, line:#C7, column:#C8, name:#C5}
|
||||
#C10 = 11.0
|
||||
#C11 = 27.0
|
||||
#C12 = "StandardWidget"
|
||||
#C13 = dart.developer::CreationLocation {file:#C2, line:#C10, column:#C11, name:#C12}
|
||||
#C14 = 14.0
|
||||
#C15 = dart.developer::CreationLocation {file:#C2, line:#C8, column:#C14, name:#C5}
|
||||
#C16 = main::MyWidget {child:#C1, _location:#C15}
|
||||
#C17 = "track-creation-locations"
|
||||
#C18 = dart.core::pragma {name:#C17, options:#C1}
|
||||
#C19 = "org-dartlang-test:///widget.dart"
|
||||
#C20 = 7.0
|
||||
#C21 = dart.developer::CreationLocation {file:#C19, line:#C20, column:#C4, name:#C12}
|
||||
#C22 = 8.0
|
||||
#C23 = dart.developer::CreationLocation {file:#C19, line:#C22, column:#C4, name:#C12}
|
||||
}
|
||||
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-test:///main.dart:
|
||||
- CreationLocation._ (from org-dartlang-sdk:///lib/developer/creation_tracking.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
- MyWidget. (from org-dartlang-test:///main.dart:4:9)
|
||||
- Widget. (from org-dartlang-test:///widget.dart:3:9)
|
||||
|
||||
org-dartlang-test:///widget.dart:
|
||||
- pragma._ (from org-dartlang-sdk:///lib/core/annotations.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
- CreationLocation._ (from org-dartlang-sdk:///lib/developer/creation_tracking.dart)
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
main = main::main;
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///widget.dart";
|
||||
|
||||
class MyWidget extends wid::Widget /*hasConstConstructor*/ {
|
||||
final field wid::Widget? child;
|
||||
const constructor •({initializing-formal wid::Widget? child = #C1, dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C1}) → main::MyWidget
|
||||
: main::MyWidget::child = child, super wid::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static synthetic method _#new#tearOff({wid::Widget? child = #C1}) → main::MyWidget
|
||||
return new main::MyWidget::•(child: child, $creationLocationd_0dea112b090073317d4: #C6);
|
||||
synthetic no-such-method-forwarder set dart.developer::_location(dart.developer::CreationLocation? value) → void
|
||||
return throw{for-error-handling} dart.core::NoSuchMethodError::withInvocation(this, new dart.core::_Invocation::setter(#C7, value));
|
||||
}
|
||||
static method main() → void {
|
||||
main::MyWidget w1 = new main::MyWidget::•(child: new wid::StandardWidget::•($creationLocationd_0dea112b090073317d4: #C11), $creationLocationd_0dea112b090073317d4: #C13);
|
||||
const main::MyWidget w2 = #C20;
|
||||
const main::MyWidget w3 = #C22;
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///widget.dart" as wid {
|
||||
|
||||
@#C24
|
||||
abstract class Widget extends dart.core::Object implements dart.developer::_HasCreationLocation /*hasConstConstructor*/ {
|
||||
final field dart.developer::CreationLocation? dart.developer::_location;
|
||||
const constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C1}) → wid::Widget
|
||||
: super dart.core::Object::•(), wid::Widget::_location = $creationLocationd_0dea112b090073317d4
|
||||
;
|
||||
}
|
||||
class StandardWidget extends wid::Widget /*hasConstConstructor*/ {
|
||||
const constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C1}) → wid::StandardWidget
|
||||
: super wid::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
const constructor named(dart.core::String name, {dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C1}) → wid::StandardWidget
|
||||
: super wid::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static synthetic method _#new#tearOff() → wid::StandardWidget
|
||||
return new wid::StandardWidget::•($creationLocationd_0dea112b090073317d4: #C27);
|
||||
static synthetic method _#named#tearOff(dart.core::String name) → wid::StandardWidget
|
||||
return new wid::StandardWidget::named(name, $creationLocationd_0dea112b090073317d4: #C29);
|
||||
}
|
||||
}
|
||||
constants {
|
||||
#C1 = null
|
||||
#C2 = "org-dartlang-test:///main.dart"
|
||||
#C3 = 4.0
|
||||
#C4 = 9.0
|
||||
#C5 = "MyWidget"
|
||||
#C6 = dart.developer::CreationLocation {file:#C2, line:#C3, column:#C4, name:#C5}
|
||||
#C7 = #org-dartlang-test:///main.dart::_location=
|
||||
#C8 = 10.0
|
||||
#C9 = 28.0
|
||||
#C10 = "StandardWidget"
|
||||
#C11 = dart.developer::CreationLocation {file:#C2, line:#C8, column:#C9, name:#C10}
|
||||
#C12 = 12.0
|
||||
#C13 = dart.developer::CreationLocation {file:#C2, line:#C8, column:#C12, name:#C5}
|
||||
#C14 = 11.0
|
||||
#C15 = 45.0
|
||||
#C16 = dart.developer::CreationLocation {file:#C2, line:#C14, column:#C15, name:#C10}
|
||||
#C17 = wid::StandardWidget {_location:#C16}
|
||||
#C18 = 14.0
|
||||
#C19 = dart.developer::CreationLocation {file:#C2, line:#C14, column:#C18, name:#C5}
|
||||
#C20 = main::MyWidget {child:#C17, _location:#C19}
|
||||
#C21 = dart.developer::CreationLocation {file:#C2, line:#C12, column:#C18, name:#C5}
|
||||
#C22 = main::MyWidget {child:#C20, _location:#C21}
|
||||
#C23 = "track-creation-locations"
|
||||
#C24 = dart.core::pragma {name:#C23, options:#C1}
|
||||
#C25 = "org-dartlang-test:///widget.dart"
|
||||
#C26 = 7.0
|
||||
#C27 = dart.developer::CreationLocation {file:#C25, line:#C26, column:#C4, name:#C10}
|
||||
#C28 = 8.0
|
||||
#C29 = dart.developer::CreationLocation {file:#C25, line:#C28, column:#C4, name:#C10}
|
||||
}
|
||||
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-test:///widget.dart:
|
||||
- pragma._ (from org-dartlang-sdk:///lib/core/annotations.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
- CreationLocation._ (from org-dartlang-sdk:///lib/developer/creation_tracking.dart)
|
||||
|
||||
org-dartlang-test:///main.dart:
|
||||
- CreationLocation._ (from org-dartlang-sdk:///lib/developer/creation_tracking.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
- StandardWidget.named (from org-dartlang-test:///widget.dart:8:9)
|
||||
- Widget. (from org-dartlang-test:///widget.dart:3:9)
|
||||
- MyWidget. (from org-dartlang-test:///main.dart:4:9)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
# for details. All rights reserved. Use of this source code is governed by a
|
||||
# BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'package:flutter/src/widgets/framework.dart';
|
||||
|
||||
class Foo extends Widget {}
|
||||
flutter/lib/src/widgets/framework.dart: |
|
||||
abstract class Bar {}
|
||||
|
||||
@pragma('track-creation-locations')
|
||||
abstract class Widget extends Bar {}
|
||||
.dart_tool/package_config.json: |
|
||||
{
|
||||
"configVersion": 2,
|
||||
"packages": [
|
||||
{
|
||||
"name": "flutter",
|
||||
"rootUri": "../flutter/lib"
|
||||
}
|
||||
]
|
||||
}
|
||||
expectedLibraryCount: 2
|
||||
- entry: main.dart
|
||||
worldType: updated
|
||||
invalidate:
|
||||
- main.dart
|
||||
expectInitializeFromDill: false
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'package:flutter/src/widgets/framework.dart';
|
||||
|
||||
class Foo extends Widget {}
|
||||
expectedLibraryCount: 2
|
||||
advancedInvalidation: bodiesOnly
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
main = <No Member>;
|
||||
library from "package:flutter/src/widgets/framework.dart" as fra {
|
||||
|
||||
abstract class Bar extends dart.core::Object {
|
||||
synthetic constructor •() → fra::Bar
|
||||
: super dart.core::Object::•()
|
||||
;
|
||||
}
|
||||
@#C3
|
||||
abstract class Widget extends fra::Bar implements dart.developer::_HasCreationLocation {
|
||||
final field dart.developer::CreationLocation? dart.developer::_location;
|
||||
synthetic constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → fra::Widget
|
||||
: super fra::Bar::•(), fra::Widget::_location = $creationLocationd_0dea112b090073317d4
|
||||
;
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "package:flutter/src/widgets/framework.dart";
|
||||
|
||||
class Foo extends fra::Widget {
|
||||
synthetic constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → main::Foo
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static synthetic method _#new#tearOff() → main::Foo
|
||||
return new main::Foo::•($creationLocationd_0dea112b090073317d4: #C8);
|
||||
}
|
||||
}
|
||||
constants {
|
||||
#C1 = "track-creation-locations"
|
||||
#C2 = null
|
||||
#C3 = dart.core::pragma {name:#C1, options:#C2}
|
||||
#C4 = "org-dartlang-test:///main.dart"
|
||||
#C5 = 3.0
|
||||
#C6 = 7.0
|
||||
#C7 = "Foo"
|
||||
#C8 = dart.developer::CreationLocation {file:#C4, line:#C5, column:#C6, name:#C7}
|
||||
}
|
||||
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-test:///main.dart:
|
||||
- CreationLocation._ (from org-dartlang-sdk:///lib/developer/creation_tracking.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
|
||||
org-dartlang-test:///flutter/lib/src/widgets/framework.dart:
|
||||
- pragma._ (from org-dartlang-sdk:///lib/core/annotations.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
main = <No Member>;
|
||||
library from "package:flutter/src/widgets/framework.dart" as fra {
|
||||
|
||||
abstract class Bar extends dart.core::Object {
|
||||
synthetic constructor •() → fra::Bar
|
||||
: super dart.core::Object::•()
|
||||
;
|
||||
}
|
||||
@#C3
|
||||
abstract class Widget extends fra::Bar implements dart.developer::_HasCreationLocation {
|
||||
final field dart.developer::CreationLocation? dart.developer::_location;
|
||||
synthetic constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → fra::Widget
|
||||
: super fra::Bar::•(), fra::Widget::_location = $creationLocationd_0dea112b090073317d4
|
||||
;
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "package:flutter/src/widgets/framework.dart";
|
||||
|
||||
class Foo extends fra::Widget {
|
||||
synthetic constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → main::Foo
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static synthetic method _#new#tearOff() → main::Foo
|
||||
return new main::Foo::•($creationLocationd_0dea112b090073317d4: #C8);
|
||||
synthetic no-such-method-forwarder set dart.developer::_location(dart.developer::CreationLocation? value) → void
|
||||
return throw{for-error-handling} dart.core::NoSuchMethodError::withInvocation(this, new dart.core::_Invocation::setter(#C9, value));
|
||||
}
|
||||
}
|
||||
constants {
|
||||
#C1 = "track-creation-locations"
|
||||
#C2 = null
|
||||
#C3 = dart.core::pragma {name:#C1, options:#C2}
|
||||
#C4 = "org-dartlang-test:///main.dart"
|
||||
#C5 = 3.0
|
||||
#C6 = 7.0
|
||||
#C7 = "Foo"
|
||||
#C8 = dart.developer::CreationLocation {file:#C4, line:#C5, column:#C6, name:#C7}
|
||||
#C9 = #org-dartlang-test:///main.dart::_location=
|
||||
}
|
||||
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-test:///flutter/lib/src/widgets/framework.dart:
|
||||
- pragma._ (from org-dartlang-sdk:///lib/core/annotations.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
|
||||
org-dartlang-test:///main.dart:
|
||||
- CreationLocation._ (from org-dartlang-sdk:///lib/developer/creation_tracking.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
# Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
# for details. All rights reserved. Use of this source code is governed by a
|
||||
# BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'foo.dart';
|
||||
Foo newFoo = new Foo();
|
||||
Bar newBar = new Bar();
|
||||
Bar constBar = const Bar();
|
||||
Baz newBaz = new Baz();
|
||||
Boz newBoz = new Boz(createNew: true);
|
||||
Boz constBoz = new Boz(createNew: false);
|
||||
foo.dart: |
|
||||
import 'package:flutter/src/widgets/framework.dart';
|
||||
|
||||
class Foo extends Widget {
|
||||
factory Foo() => const Foo._();
|
||||
|
||||
const Foo._();
|
||||
}
|
||||
|
||||
class Bar extends Widget {
|
||||
const factory Bar() = Bar._;
|
||||
|
||||
const Bar._();
|
||||
}
|
||||
|
||||
class Baz extends Widget {
|
||||
factory Baz() => const Baz._();
|
||||
|
||||
const factory Baz._() = Baz.__;
|
||||
|
||||
const Baz.__();
|
||||
}
|
||||
|
||||
class Boz extends Widget {
|
||||
factory Boz({required bool createNew}) {
|
||||
if (createNew) {
|
||||
return new Boz._();
|
||||
} else {
|
||||
return const Boz._();
|
||||
}
|
||||
}
|
||||
|
||||
const Boz._();
|
||||
}
|
||||
flutter/lib/src/widgets/framework.dart: |
|
||||
abstract class Bar {
|
||||
const Bar();
|
||||
}
|
||||
@pragma('track-creation-locations')
|
||||
abstract class Widget extends Bar {
|
||||
const Widget();
|
||||
}
|
||||
.dart_tool/package_config.json: |
|
||||
{
|
||||
"configVersion": 2,
|
||||
"packages": [
|
||||
{
|
||||
"name": "flutter",
|
||||
"rootUri": "../flutter",
|
||||
"packageUri": "lib/"
|
||||
}
|
||||
]
|
||||
}
|
||||
expectedLibraryCount: 3
|
||||
|
||||
- entry: main.dart
|
||||
worldType: updated
|
||||
invalidate:
|
||||
- main.dart
|
||||
expectInitializeFromDill: false
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'foo.dart';
|
||||
expectedLibraryCount: 3
|
||||
advancedInvalidation: outlineChange
|
||||
|
||||
- entry: main.dart
|
||||
worldType: updated
|
||||
invalidate:
|
||||
- main.dart
|
||||
expectInitializeFromDill: false
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'foo.dart';
|
||||
Foo newFoo = new Foo();
|
||||
Bar newBar = new Bar();
|
||||
Bar constBar = const Bar();
|
||||
Baz newBaz = new Baz();
|
||||
Boz newBoz = new Boz(createNew: true);
|
||||
Boz constBoz = new Boz(createNew: false);
|
||||
expectedLibraryCount: 3
|
||||
advancedInvalidation: outlineChange
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
main = <No Member>;
|
||||
library from "package:flutter/src/widgets/framework.dart" as fra {
|
||||
|
||||
abstract class Bar extends dart.core::Object /*hasConstConstructor*/ {
|
||||
const constructor •() → fra::Bar
|
||||
: super dart.core::Object::•()
|
||||
;
|
||||
}
|
||||
@#C3
|
||||
abstract class Widget extends fra::Bar implements dart.developer::_HasCreationLocation /*hasConstConstructor*/ {
|
||||
final field dart.developer::CreationLocation? dart.developer::_location;
|
||||
const constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → fra::Widget
|
||||
: super fra::Bar::•(), fra::Widget::_location = $creationLocationd_0dea112b090073317d4
|
||||
;
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///foo.dart" as foo {
|
||||
|
||||
import "package:flutter/src/widgets/framework.dart";
|
||||
|
||||
class Foo extends fra::Widget /*hasConstConstructor*/ {
|
||||
const constructor _({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Foo
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static factory •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Foo
|
||||
return #C9;
|
||||
static synthetic method _#new#tearOff() → foo::Foo
|
||||
return foo::Foo::•($creationLocationd_0dea112b090073317d4: #C11);
|
||||
static synthetic method _#_#tearOff() → foo::Foo
|
||||
return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C14);
|
||||
}
|
||||
class Bar extends fra::Widget /*hasConstConstructor*/ {
|
||||
const constructor _({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Bar
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static const factory •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Bar /* redirection-target: foo::Bar::_ */
|
||||
return new foo::Bar::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
|
||||
static synthetic method _#new#tearOff() → foo::Bar
|
||||
return new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C18);
|
||||
static synthetic method _#_#tearOff() → foo::Bar
|
||||
return new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C20);
|
||||
}
|
||||
class Baz extends fra::Widget /*hasConstConstructor*/ {
|
||||
const constructor __({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Baz
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static factory •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Baz
|
||||
return #C24;
|
||||
static synthetic method _#new#tearOff() → foo::Baz
|
||||
return foo::Baz::•($creationLocationd_0dea112b090073317d4: #C25);
|
||||
static const factory _({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Baz /* redirection-target: foo::Baz::__ */
|
||||
return new foo::Baz::__($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
|
||||
static synthetic method _#_#tearOff() → foo::Baz
|
||||
return new foo::Baz::__($creationLocationd_0dea112b090073317d4: #C27);
|
||||
static synthetic method _#__#tearOff() → foo::Baz
|
||||
return new foo::Baz::__($creationLocationd_0dea112b090073317d4: #C29);
|
||||
}
|
||||
class Boz extends fra::Widget /*hasConstConstructor*/ {
|
||||
const constructor _({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Boz
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static factory •({required dart.core::bool createNew, dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Boz {
|
||||
if(createNew) {
|
||||
return new foo::Boz::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
|
||||
}
|
||||
else {
|
||||
return #C33;
|
||||
}
|
||||
}
|
||||
static synthetic method _#new#tearOff({required dart.core::bool createNew}) → foo::Boz
|
||||
return foo::Boz::•(createNew: createNew, $creationLocationd_0dea112b090073317d4: #C35);
|
||||
static synthetic method _#_#tearOff() → foo::Boz
|
||||
return new foo::Boz::_($creationLocationd_0dea112b090073317d4: #C37);
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///foo.dart";
|
||||
|
||||
static field foo::Foo newFoo = foo::Foo::•($creationLocationd_0dea112b090073317d4: #C40);
|
||||
static field foo::Bar newBar = new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C42);
|
||||
static field foo::Bar constBar = #C45;
|
||||
static field foo::Baz newBaz = foo::Baz::•($creationLocationd_0dea112b090073317d4: #C47);
|
||||
static field foo::Boz newBoz = foo::Boz::•(createNew: true, $creationLocationd_0dea112b090073317d4: #C48);
|
||||
static field foo::Boz constBoz = foo::Boz::•(createNew: false, $creationLocationd_0dea112b090073317d4: #C50);
|
||||
}
|
||||
constants {
|
||||
#C1 = "track-creation-locations"
|
||||
#C2 = null
|
||||
#C3 = dart.core::pragma {name:#C1, options:#C2}
|
||||
#C4 = "org-dartlang-test:///foo.dart"
|
||||
#C5 = 4.0
|
||||
#C6 = 26.0
|
||||
#C7 = "Foo"
|
||||
#C8 = dart.developer::CreationLocation {file:#C4, line:#C5, column:#C6, name:#C7}
|
||||
#C9 = foo::Foo {_location:#C8}
|
||||
#C10 = 11.0
|
||||
#C11 = dart.developer::CreationLocation {file:#C4, line:#C5, column:#C10, name:#C7}
|
||||
#C12 = 6.0
|
||||
#C13 = 9.0
|
||||
#C14 = dart.developer::CreationLocation {file:#C4, line:#C12, column:#C13, name:#C7}
|
||||
#C15 = 10.0
|
||||
#C16 = 17.0
|
||||
#C17 = "Bar"
|
||||
#C18 = dart.developer::CreationLocation {file:#C4, line:#C15, column:#C16, name:#C17}
|
||||
#C19 = 12.0
|
||||
#C20 = dart.developer::CreationLocation {file:#C4, line:#C19, column:#C13, name:#C17}
|
||||
#C21 = 16.0
|
||||
#C22 = "Baz"
|
||||
#C23 = dart.developer::CreationLocation {file:#C4, line:#C21, column:#C6, name:#C22}
|
||||
#C24 = foo::Baz {_location:#C23}
|
||||
#C25 = dart.developer::CreationLocation {file:#C4, line:#C21, column:#C10, name:#C22}
|
||||
#C26 = 18.0
|
||||
#C27 = dart.developer::CreationLocation {file:#C4, line:#C26, column:#C16, name:#C22}
|
||||
#C28 = 20.0
|
||||
#C29 = dart.developer::CreationLocation {file:#C4, line:#C28, column:#C13, name:#C22}
|
||||
#C30 = 28.0
|
||||
#C31 = "Boz"
|
||||
#C32 = dart.developer::CreationLocation {file:#C4, line:#C30, column:#C28, name:#C31}
|
||||
#C33 = foo::Boz {_location:#C32}
|
||||
#C34 = 24.0
|
||||
#C35 = dart.developer::CreationLocation {file:#C4, line:#C34, column:#C10, name:#C31}
|
||||
#C36 = 32.0
|
||||
#C37 = dart.developer::CreationLocation {file:#C4, line:#C36, column:#C13, name:#C31}
|
||||
#C38 = "org-dartlang-test:///main.dart"
|
||||
#C39 = 2.0
|
||||
#C40 = dart.developer::CreationLocation {file:#C38, line:#C39, column:#C26, name:#C7}
|
||||
#C41 = 3.0
|
||||
#C42 = dart.developer::CreationLocation {file:#C38, line:#C41, column:#C26, name:#C17}
|
||||
#C43 = 22.0
|
||||
#C44 = dart.developer::CreationLocation {file:#C38, line:#C5, column:#C43, name:#C17}
|
||||
#C45 = foo::Bar {_location:#C44}
|
||||
#C46 = 5.0
|
||||
#C47 = dart.developer::CreationLocation {file:#C38, line:#C46, column:#C26, name:#C22}
|
||||
#C48 = dart.developer::CreationLocation {file:#C38, line:#C12, column:#C26, name:#C31}
|
||||
#C49 = 7.0
|
||||
#C50 = dart.developer::CreationLocation {file:#C38, line:#C49, column:#C28, name:#C31}
|
||||
}
|
||||
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-test:///main.dart:
|
||||
- CreationLocation._ (from org-dartlang-sdk:///lib/developer/creation_tracking.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
- Bar._ (from org-dartlang-test:///foo.dart:12:9)
|
||||
- Widget. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:6:9)
|
||||
- Bar. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:2:9)
|
||||
|
||||
org-dartlang-test:///foo.dart:
|
||||
- CreationLocation._ (from org-dartlang-sdk:///lib/developer/creation_tracking.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
- Foo._ (from org-dartlang-test:///foo.dart:6:9)
|
||||
- Widget. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:6:9)
|
||||
- Bar. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:2:9)
|
||||
- Baz.__ (from org-dartlang-test:///foo.dart:20:9)
|
||||
- Boz._ (from org-dartlang-test:///foo.dart:32:9)
|
||||
|
||||
org-dartlang-test:///flutter/lib/src/widgets/framework.dart:
|
||||
- pragma._ (from org-dartlang-sdk:///lib/core/annotations.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
main = <No Member>;
|
||||
library from "package:flutter/src/widgets/framework.dart" as fra {
|
||||
|
||||
abstract class Bar extends dart.core::Object /*hasConstConstructor*/ {
|
||||
const constructor •() → fra::Bar
|
||||
: super dart.core::Object::•()
|
||||
;
|
||||
}
|
||||
@#C3
|
||||
abstract class Widget extends fra::Bar implements dart.developer::_HasCreationLocation /*hasConstConstructor*/ {
|
||||
final field dart.developer::CreationLocation? dart.developer::_location;
|
||||
const constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → fra::Widget
|
||||
: super fra::Bar::•(), fra::Widget::_location = $creationLocationd_0dea112b090073317d4
|
||||
;
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///foo.dart" as foo {
|
||||
|
||||
import "package:flutter/src/widgets/framework.dart";
|
||||
|
||||
class Foo extends fra::Widget /*hasConstConstructor*/ {
|
||||
const constructor _({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Foo
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static factory •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Foo
|
||||
return #C9;
|
||||
static synthetic method _#new#tearOff() → foo::Foo
|
||||
return foo::Foo::•($creationLocationd_0dea112b090073317d4: #C11);
|
||||
static synthetic method _#_#tearOff() → foo::Foo
|
||||
return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C14);
|
||||
}
|
||||
class Bar extends fra::Widget /*hasConstConstructor*/ {
|
||||
const constructor _({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Bar
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static const factory •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Bar /* redirection-target: foo::Bar::_ */
|
||||
return new foo::Bar::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
|
||||
static synthetic method _#new#tearOff() → foo::Bar
|
||||
return new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C18);
|
||||
static synthetic method _#_#tearOff() → foo::Bar
|
||||
return new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C20);
|
||||
}
|
||||
class Baz extends fra::Widget /*hasConstConstructor*/ {
|
||||
const constructor __({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Baz
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static factory •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Baz
|
||||
return #C24;
|
||||
static synthetic method _#new#tearOff() → foo::Baz
|
||||
return foo::Baz::•($creationLocationd_0dea112b090073317d4: #C25);
|
||||
static const factory _({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Baz /* redirection-target: foo::Baz::__ */
|
||||
return new foo::Baz::__($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
|
||||
static synthetic method _#_#tearOff() → foo::Baz
|
||||
return new foo::Baz::__($creationLocationd_0dea112b090073317d4: #C27);
|
||||
static synthetic method _#__#tearOff() → foo::Baz
|
||||
return new foo::Baz::__($creationLocationd_0dea112b090073317d4: #C29);
|
||||
}
|
||||
class Boz extends fra::Widget /*hasConstConstructor*/ {
|
||||
const constructor _({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Boz
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static factory •({required dart.core::bool createNew, dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Boz {
|
||||
if(createNew) {
|
||||
return new foo::Boz::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
|
||||
}
|
||||
else {
|
||||
return #C33;
|
||||
}
|
||||
}
|
||||
static synthetic method _#new#tearOff({required dart.core::bool createNew}) → foo::Boz
|
||||
return foo::Boz::•(createNew: createNew, $creationLocationd_0dea112b090073317d4: #C35);
|
||||
static synthetic method _#_#tearOff() → foo::Boz
|
||||
return new foo::Boz::_($creationLocationd_0dea112b090073317d4: #C37);
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///foo.dart";
|
||||
|
||||
}
|
||||
constants {
|
||||
#C1 = "track-creation-locations"
|
||||
#C2 = null
|
||||
#C3 = dart.core::pragma {name:#C1, options:#C2}
|
||||
#C4 = "org-dartlang-test:///foo.dart"
|
||||
#C5 = 4.0
|
||||
#C6 = 26.0
|
||||
#C7 = "Foo"
|
||||
#C8 = dart.developer::CreationLocation {file:#C4, line:#C5, column:#C6, name:#C7}
|
||||
#C9 = foo::Foo {_location:#C8}
|
||||
#C10 = 11.0
|
||||
#C11 = dart.developer::CreationLocation {file:#C4, line:#C5, column:#C10, name:#C7}
|
||||
#C12 = 6.0
|
||||
#C13 = 9.0
|
||||
#C14 = dart.developer::CreationLocation {file:#C4, line:#C12, column:#C13, name:#C7}
|
||||
#C15 = 10.0
|
||||
#C16 = 17.0
|
||||
#C17 = "Bar"
|
||||
#C18 = dart.developer::CreationLocation {file:#C4, line:#C15, column:#C16, name:#C17}
|
||||
#C19 = 12.0
|
||||
#C20 = dart.developer::CreationLocation {file:#C4, line:#C19, column:#C13, name:#C17}
|
||||
#C21 = 16.0
|
||||
#C22 = "Baz"
|
||||
#C23 = dart.developer::CreationLocation {file:#C4, line:#C21, column:#C6, name:#C22}
|
||||
#C24 = foo::Baz {_location:#C23}
|
||||
#C25 = dart.developer::CreationLocation {file:#C4, line:#C21, column:#C10, name:#C22}
|
||||
#C26 = 18.0
|
||||
#C27 = dart.developer::CreationLocation {file:#C4, line:#C26, column:#C16, name:#C22}
|
||||
#C28 = 20.0
|
||||
#C29 = dart.developer::CreationLocation {file:#C4, line:#C28, column:#C13, name:#C22}
|
||||
#C30 = 28.0
|
||||
#C31 = "Boz"
|
||||
#C32 = dart.developer::CreationLocation {file:#C4, line:#C30, column:#C28, name:#C31}
|
||||
#C33 = foo::Boz {_location:#C32}
|
||||
#C34 = 24.0
|
||||
#C35 = dart.developer::CreationLocation {file:#C4, line:#C34, column:#C10, name:#C31}
|
||||
#C36 = 32.0
|
||||
#C37 = dart.developer::CreationLocation {file:#C4, line:#C36, column:#C13, name:#C31}
|
||||
}
|
||||
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-test:///foo.dart:
|
||||
- CreationLocation._ (from org-dartlang-sdk:///lib/developer/creation_tracking.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
- Foo._ (from org-dartlang-test:///foo.dart:6:9)
|
||||
- Widget. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:6:9)
|
||||
- Bar. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:2:9)
|
||||
- Baz.__ (from org-dartlang-test:///foo.dart:20:9)
|
||||
- Boz._ (from org-dartlang-test:///foo.dart:32:9)
|
||||
|
||||
org-dartlang-test:///flutter/lib/src/widgets/framework.dart:
|
||||
- pragma._ (from org-dartlang-sdk:///lib/core/annotations.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
main = <No Member>;
|
||||
library from "package:flutter/src/widgets/framework.dart" as fra {
|
||||
|
||||
abstract class Bar extends dart.core::Object /*hasConstConstructor*/ {
|
||||
const constructor •() → fra::Bar
|
||||
: super dart.core::Object::•()
|
||||
;
|
||||
}
|
||||
@#C3
|
||||
abstract class Widget extends fra::Bar implements dart.developer::_HasCreationLocation /*hasConstConstructor*/ {
|
||||
final field dart.developer::CreationLocation? dart.developer::_location;
|
||||
const constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → fra::Widget
|
||||
: super fra::Bar::•(), fra::Widget::_location = $creationLocationd_0dea112b090073317d4
|
||||
;
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///foo.dart" as foo {
|
||||
|
||||
import "package:flutter/src/widgets/framework.dart";
|
||||
|
||||
class Foo extends fra::Widget /*hasConstConstructor*/ {
|
||||
const constructor _({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Foo
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static factory •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Foo
|
||||
return #C9;
|
||||
static synthetic method _#new#tearOff() → foo::Foo
|
||||
return foo::Foo::•($creationLocationd_0dea112b090073317d4: #C11);
|
||||
static synthetic method _#_#tearOff() → foo::Foo
|
||||
return new foo::Foo::_($creationLocationd_0dea112b090073317d4: #C14);
|
||||
}
|
||||
class Bar extends fra::Widget /*hasConstConstructor*/ {
|
||||
const constructor _({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Bar
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static const factory •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Bar /* redirection-target: foo::Bar::_ */
|
||||
return new foo::Bar::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
|
||||
static synthetic method _#new#tearOff() → foo::Bar
|
||||
return new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C18);
|
||||
static synthetic method _#_#tearOff() → foo::Bar
|
||||
return new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C20);
|
||||
}
|
||||
class Baz extends fra::Widget /*hasConstConstructor*/ {
|
||||
const constructor __({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Baz
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static factory •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Baz
|
||||
return #C24;
|
||||
static synthetic method _#new#tearOff() → foo::Baz
|
||||
return foo::Baz::•($creationLocationd_0dea112b090073317d4: #C25);
|
||||
static const factory _({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Baz /* redirection-target: foo::Baz::__ */
|
||||
return new foo::Baz::__($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
|
||||
static synthetic method _#_#tearOff() → foo::Baz
|
||||
return new foo::Baz::__($creationLocationd_0dea112b090073317d4: #C27);
|
||||
static synthetic method _#__#tearOff() → foo::Baz
|
||||
return new foo::Baz::__($creationLocationd_0dea112b090073317d4: #C29);
|
||||
}
|
||||
class Boz extends fra::Widget /*hasConstConstructor*/ {
|
||||
const constructor _({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Boz
|
||||
: super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static factory •({required dart.core::bool createNew, dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → foo::Boz {
|
||||
if(createNew) {
|
||||
return new foo::Boz::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
|
||||
}
|
||||
else {
|
||||
return #C33;
|
||||
}
|
||||
}
|
||||
static synthetic method _#new#tearOff({required dart.core::bool createNew}) → foo::Boz
|
||||
return foo::Boz::•(createNew: createNew, $creationLocationd_0dea112b090073317d4: #C35);
|
||||
static synthetic method _#_#tearOff() → foo::Boz
|
||||
return new foo::Boz::_($creationLocationd_0dea112b090073317d4: #C37);
|
||||
}
|
||||
}
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///foo.dart";
|
||||
|
||||
static field foo::Foo newFoo = foo::Foo::•($creationLocationd_0dea112b090073317d4: #C40);
|
||||
static field foo::Bar newBar = new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C42);
|
||||
static field foo::Bar constBar = #C45;
|
||||
static field foo::Baz newBaz = foo::Baz::•($creationLocationd_0dea112b090073317d4: #C47);
|
||||
static field foo::Boz newBoz = foo::Boz::•(createNew: true, $creationLocationd_0dea112b090073317d4: #C48);
|
||||
static field foo::Boz constBoz = foo::Boz::•(createNew: false, $creationLocationd_0dea112b090073317d4: #C50);
|
||||
}
|
||||
constants {
|
||||
#C1 = "track-creation-locations"
|
||||
#C2 = null
|
||||
#C3 = dart.core::pragma {name:#C1, options:#C2}
|
||||
#C4 = "org-dartlang-test:///foo.dart"
|
||||
#C5 = 4.0
|
||||
#C6 = 26.0
|
||||
#C7 = "Foo"
|
||||
#C8 = dart.developer::CreationLocation {file:#C4, line:#C5, column:#C6, name:#C7}
|
||||
#C9 = foo::Foo {_location:#C8}
|
||||
#C10 = 11.0
|
||||
#C11 = dart.developer::CreationLocation {file:#C4, line:#C5, column:#C10, name:#C7}
|
||||
#C12 = 6.0
|
||||
#C13 = 9.0
|
||||
#C14 = dart.developer::CreationLocation {file:#C4, line:#C12, column:#C13, name:#C7}
|
||||
#C15 = 10.0
|
||||
#C16 = 17.0
|
||||
#C17 = "Bar"
|
||||
#C18 = dart.developer::CreationLocation {file:#C4, line:#C15, column:#C16, name:#C17}
|
||||
#C19 = 12.0
|
||||
#C20 = dart.developer::CreationLocation {file:#C4, line:#C19, column:#C13, name:#C17}
|
||||
#C21 = 16.0
|
||||
#C22 = "Baz"
|
||||
#C23 = dart.developer::CreationLocation {file:#C4, line:#C21, column:#C6, name:#C22}
|
||||
#C24 = foo::Baz {_location:#C23}
|
||||
#C25 = dart.developer::CreationLocation {file:#C4, line:#C21, column:#C10, name:#C22}
|
||||
#C26 = 18.0
|
||||
#C27 = dart.developer::CreationLocation {file:#C4, line:#C26, column:#C16, name:#C22}
|
||||
#C28 = 20.0
|
||||
#C29 = dart.developer::CreationLocation {file:#C4, line:#C28, column:#C13, name:#C22}
|
||||
#C30 = 28.0
|
||||
#C31 = "Boz"
|
||||
#C32 = dart.developer::CreationLocation {file:#C4, line:#C30, column:#C28, name:#C31}
|
||||
#C33 = foo::Boz {_location:#C32}
|
||||
#C34 = 24.0
|
||||
#C35 = dart.developer::CreationLocation {file:#C4, line:#C34, column:#C10, name:#C31}
|
||||
#C36 = 32.0
|
||||
#C37 = dart.developer::CreationLocation {file:#C4, line:#C36, column:#C13, name:#C31}
|
||||
#C38 = "org-dartlang-test:///main.dart"
|
||||
#C39 = 2.0
|
||||
#C40 = dart.developer::CreationLocation {file:#C38, line:#C39, column:#C26, name:#C7}
|
||||
#C41 = 3.0
|
||||
#C42 = dart.developer::CreationLocation {file:#C38, line:#C41, column:#C26, name:#C17}
|
||||
#C43 = 22.0
|
||||
#C44 = dart.developer::CreationLocation {file:#C38, line:#C5, column:#C43, name:#C17}
|
||||
#C45 = foo::Bar {_location:#C44}
|
||||
#C46 = 5.0
|
||||
#C47 = dart.developer::CreationLocation {file:#C38, line:#C46, column:#C26, name:#C22}
|
||||
#C48 = dart.developer::CreationLocation {file:#C38, line:#C12, column:#C26, name:#C31}
|
||||
#C49 = 7.0
|
||||
#C50 = dart.developer::CreationLocation {file:#C38, line:#C49, column:#C28, name:#C31}
|
||||
}
|
||||
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-test:///foo.dart:
|
||||
- CreationLocation._ (from org-dartlang-sdk:///lib/developer/creation_tracking.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
- Foo._ (from org-dartlang-test:///foo.dart:6:9)
|
||||
- Widget. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:6:9)
|
||||
- Bar. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:2:9)
|
||||
- Baz.__ (from org-dartlang-test:///foo.dart:20:9)
|
||||
- Boz._ (from org-dartlang-test:///foo.dart:32:9)
|
||||
|
||||
org-dartlang-test:///flutter/lib/src/widgets/framework.dart:
|
||||
- pragma._ (from org-dartlang-sdk:///lib/core/annotations.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
|
||||
org-dartlang-test:///main.dart:
|
||||
- CreationLocation._ (from org-dartlang-sdk:///lib/developer/creation_tracking.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
- Bar._ (from org-dartlang-test:///foo.dart:12:9)
|
||||
- Widget. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:6:9)
|
||||
- Bar. (from org-dartlang-test:///flutter/lib/src/widgets/framework.dart:2:9)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
# for details. All rights reserved. Use of this source code is governed by a
|
||||
# BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
# This tests that Jaspr-style components, including redirecting factory
|
||||
# constructors, are correctly transformed to include tracking information.
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
sources:
|
||||
main.dart: |
|
||||
@pragma('track-creation-locations')
|
||||
abstract class Component {
|
||||
const Component({this.key});
|
||||
|
||||
const factory Component.text(String text, {String? key}) = Text._;
|
||||
|
||||
final String? key;
|
||||
}
|
||||
|
||||
class Text extends Component {
|
||||
const Text._(this.text, {super.key});
|
||||
|
||||
final String text;
|
||||
}
|
||||
|
||||
class MyComponent extends Component {
|
||||
const MyComponent(this.children, {this.id, super.key});
|
||||
|
||||
final List<Component> children;
|
||||
final String? id;
|
||||
}
|
||||
|
||||
void main() {
|
||||
var c1 = MyComponent([]);
|
||||
var c2 = MyComponent([c1], id: '2');
|
||||
|
||||
const c3 = MyComponent([Component.text('Hello')]);
|
||||
const c4 = MyComponent([c3, MyComponent([], id: 'x')], id: '4');
|
||||
}
|
||||
expectedLibraryCount: 1
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
main = main::main;
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
@#C3
|
||||
abstract class Component extends dart.core::Object implements dart.developer::_HasCreationLocation /*hasConstConstructor*/ {
|
||||
final field dart.core::String? key;
|
||||
final field dart.developer::CreationLocation? dart.developer::_location;
|
||||
const constructor •({initializing-formal dart.core::String? key = #C2, dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → main::Component
|
||||
: main::Component::key = key, super dart.core::Object::•(), main::Component::_location = $creationLocationd_0dea112b090073317d4
|
||||
;
|
||||
static const factory text(dart.core::String text, {dart.core::String? key = #C2, dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → main::Component /* redirection-target: main::Text::_ */
|
||||
return new main::Text::_(text, key: key, $creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
|
||||
static synthetic method _#text#tearOff(dart.core::String text, {dart.core::String? key = #C2}) → main::Component
|
||||
return new main::Text::_(text, key: key, $creationLocationd_0dea112b090073317d4: #C8);
|
||||
}
|
||||
class Text extends main::Component /*hasConstConstructor*/ {
|
||||
final field dart.core::String text;
|
||||
const constructor _(initializing-formal dart.core::String text, {super-initializing-formal dart.core::String? key = #C2, dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → main::Text
|
||||
: main::Text::text = text, super main::Component::•(key: key, $creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static synthetic method _#_#tearOff(dart.core::String text, {dart.core::String? key = #C2}) → main::Text
|
||||
return new main::Text::_(text, key: key, $creationLocationd_0dea112b090073317d4: #C11);
|
||||
}
|
||||
class MyComponent extends main::Component /*hasConstConstructor*/ {
|
||||
final field dart.core::List<main::Component> children;
|
||||
final field dart.core::String? id;
|
||||
const constructor •(initializing-formal dart.core::List<main::Component> children, {initializing-formal dart.core::String? id = #C2, super-initializing-formal dart.core::String? key = #C2, dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = #C2}) → main::MyComponent
|
||||
: main::MyComponent::children = children, main::MyComponent::id = id, super main::Component::•(key: key, $creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static synthetic method _#new#tearOff(dart.core::List<main::Component> children, {dart.core::String? id = #C2, dart.core::String? key = #C2}) → main::MyComponent
|
||||
return new main::MyComponent::•(children, id: id, key: key, $creationLocationd_0dea112b090073317d4: #C13);
|
||||
}
|
||||
static method main() → void {
|
||||
main::MyComponent c1 = new main::MyComponent::•(<main::Component>[], $creationLocationd_0dea112b090073317d4: #C16);
|
||||
main::MyComponent c2 = new main::MyComponent::•(<main::Component>[c1], id: "2", $creationLocationd_0dea112b090073317d4: #C18);
|
||||
const main::MyComponent c3 = #C27;
|
||||
const main::MyComponent c4 = #C37;
|
||||
}
|
||||
}
|
||||
constants {
|
||||
#C1 = "track-creation-locations"
|
||||
#C2 = null
|
||||
#C3 = dart.core::pragma {name:#C1, options:#C2}
|
||||
#C4 = "org-dartlang-test:///main.dart"
|
||||
#C5 = 5.0
|
||||
#C6 = 17.0
|
||||
#C7 = "Text"
|
||||
#C8 = dart.developer::CreationLocation {file:#C4, line:#C5, column:#C6, name:#C7}
|
||||
#C9 = 11.0
|
||||
#C10 = 9.0
|
||||
#C11 = dart.developer::CreationLocation {file:#C4, line:#C9, column:#C10, name:#C7}
|
||||
#C12 = "MyComponent"
|
||||
#C13 = dart.developer::CreationLocation {file:#C4, line:#C6, column:#C10, name:#C12}
|
||||
#C14 = 24.0
|
||||
#C15 = 12.0
|
||||
#C16 = dart.developer::CreationLocation {file:#C4, line:#C14, column:#C15, name:#C12}
|
||||
#C17 = 25.0
|
||||
#C18 = dart.developer::CreationLocation {file:#C4, line:#C17, column:#C15, name:#C12}
|
||||
#C19 = "Hello"
|
||||
#C20 = 27.0
|
||||
#C21 = 37.0
|
||||
#C22 = dart.developer::CreationLocation {file:#C4, line:#C20, column:#C21, name:#C7}
|
||||
#C23 = main::Text {text:#C19, key:#C2, _location:#C22}
|
||||
#C24 = <main::Component>[#C23]
|
||||
#C25 = 14.0
|
||||
#C26 = dart.developer::CreationLocation {file:#C4, line:#C20, column:#C25, name:#C12}
|
||||
#C27 = main::MyComponent {children:#C24, id:#C2, key:#C2, _location:#C26}
|
||||
#C28 = <main::Component>[]
|
||||
#C29 = "x"
|
||||
#C30 = 28.0
|
||||
#C31 = 31.0
|
||||
#C32 = dart.developer::CreationLocation {file:#C4, line:#C30, column:#C31, name:#C12}
|
||||
#C33 = main::MyComponent {children:#C28, id:#C29, key:#C2, _location:#C32}
|
||||
#C34 = <main::Component>[#C27, #C33]
|
||||
#C35 = "4"
|
||||
#C36 = dart.developer::CreationLocation {file:#C4, line:#C30, column:#C25, name:#C12}
|
||||
#C37 = main::MyComponent {children:#C34, id:#C35, key:#C2, _location:#C36}
|
||||
}
|
||||
|
||||
|
||||
Constructor coverage from constants:
|
||||
org-dartlang-test:///main.dart:
|
||||
- pragma._ (from org-dartlang-sdk:///lib/core/annotations.dart)
|
||||
- Object. (from org-dartlang-sdk:///lib/core/object.dart)
|
||||
- CreationLocation._ (from org-dartlang-sdk:///lib/developer/creation_tracking.dart)
|
||||
- Text._ (from org-dartlang-test:///main.dart:11:9)
|
||||
- Component. (from org-dartlang-test:///main.dart:3:9)
|
||||
- MyComponent. (from org-dartlang-test:///main.dart:17:9)
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
# for details. All rights reserved. Use of this source code is governed by a
|
||||
# BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
outlineOnly: true
|
||||
skipOutlineBodyCheck: true
|
||||
sources:
|
||||
widget.dart: |
|
||||
import 'dart:developer';
|
||||
|
||||
@pragma('track-creation-locations')
|
||||
abstract class Widget {
|
||||
const Widget();
|
||||
}
|
||||
|
||||
class StandardWidget extends Widget {
|
||||
const StandardWidget();
|
||||
const StandardWidget.named(String name);
|
||||
}
|
||||
main.dart: |
|
||||
import 'widget.dart';
|
||||
|
||||
class MyWidget extends Widget {
|
||||
const MyWidget({this.child});
|
||||
|
||||
final Widget? child;
|
||||
}
|
||||
|
||||
void main() {
|
||||
var w1 = MyWidget();
|
||||
var w2 = StandardWidget.named('w2');
|
||||
const w3 = MyWidget();
|
||||
}
|
||||
expectedLibraryCount: 2
|
||||
|
||||
- entry: main.dart
|
||||
worldType: updated
|
||||
outlineOnly: true
|
||||
skipOutlineBodyCheck: true
|
||||
expectInitializeFromDill: false
|
||||
invalidate:
|
||||
- main.dart
|
||||
sources:
|
||||
main.dart: |
|
||||
import 'widget.dart';
|
||||
|
||||
class MyWidget extends Widget {
|
||||
const MyWidget({this.child});
|
||||
|
||||
final Widget? child;
|
||||
}
|
||||
|
||||
void main() {
|
||||
var w1 = MyWidget(child: StandardWidget());
|
||||
const w2 = MyWidget(child: StandardWidget.named('w2'));
|
||||
const w3 = MyWidget(child: w2);
|
||||
}
|
||||
expectedLibraryCount: 2
|
||||
advancedInvalidation: bodiesOnly
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
main = main::main;
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///widget.dart";
|
||||
|
||||
class MyWidget extends wid::Widget /*hasConstConstructor*/ {
|
||||
final field wid::Widget? child;
|
||||
const constructor •({initializing-formal wid::Widget? child = null, dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = null}) → main::MyWidget
|
||||
: main::MyWidget::child = child, super wid::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static synthetic method _#new#tearOff({wid::Widget? child}) → main::MyWidget
|
||||
return new main::MyWidget::•(child: child, $creationLocationd_0dea112b090073317d4: const dart.developer::CreationLocation::_(file: "org-dartlang-test:///main.dart", line: 4, column: 9, name: "MyWidget"));
|
||||
}
|
||||
static method main() → void
|
||||
;
|
||||
}
|
||||
library from "org-dartlang-test:///widget.dart" as wid {
|
||||
|
||||
import "dart:developer";
|
||||
|
||||
@/*original=dart.core::pragma::•*/ const dart.core::pragma::_("track-creation-locations")
|
||||
abstract class Widget extends dart.core::Object implements dart.developer::_HasCreationLocation /*hasConstConstructor*/ {
|
||||
final field dart.developer::CreationLocation? dart.developer::_location;
|
||||
const constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = null}) → wid::Widget
|
||||
: super dart.core::Object::•(), wid::Widget::_location = $creationLocationd_0dea112b090073317d4
|
||||
;
|
||||
}
|
||||
class StandardWidget extends wid::Widget /*hasConstConstructor*/ {
|
||||
const constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = null}) → wid::StandardWidget
|
||||
: super wid::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
const constructor named(dart.core::String name, {dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = null}) → wid::StandardWidget
|
||||
: super wid::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static synthetic method _#new#tearOff() → wid::StandardWidget
|
||||
return new wid::StandardWidget::•($creationLocationd_0dea112b090073317d4: const dart.developer::CreationLocation::_(file: "org-dartlang-test:///widget.dart", line: 9, column: 9, name: "StandardWidget"));
|
||||
static synthetic method _#named#tearOff(dart.core::String name) → wid::StandardWidget
|
||||
return new wid::StandardWidget::named(name, $creationLocationd_0dea112b090073317d4: const dart.developer::CreationLocation::_(file: "org-dartlang-test:///widget.dart", line: 10, column: 9, name: "StandardWidget"));
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
main = main::main;
|
||||
library from "org-dartlang-test:///main.dart" as main {
|
||||
|
||||
import "org-dartlang-test:///widget.dart";
|
||||
|
||||
class MyWidget extends wid::Widget /*hasConstConstructor*/ {
|
||||
final field wid::Widget? child;
|
||||
const constructor •({initializing-formal wid::Widget? child = null, dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = null}) → main::MyWidget
|
||||
: main::MyWidget::child = child, super wid::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static synthetic method _#new#tearOff({wid::Widget? child}) → main::MyWidget
|
||||
return new main::MyWidget::•(child: child, $creationLocationd_0dea112b090073317d4: const dart.developer::CreationLocation::_(file: "org-dartlang-test:///main.dart", line: 4, column: 9, name: "MyWidget"));
|
||||
synthetic no-such-method-forwarder set dart.developer::_location(dart.developer::CreationLocation? value) → void
|
||||
return throw{for-error-handling} dart.core::NoSuchMethodError::withInvocation(this, new dart.core::_Invocation::setter(#_location=, value));
|
||||
}
|
||||
static method main() → void
|
||||
;
|
||||
}
|
||||
library from "org-dartlang-test:///widget.dart" as wid {
|
||||
|
||||
import "dart:developer";
|
||||
|
||||
@/*original=dart.core::pragma::•*/ const dart.core::pragma::_("track-creation-locations")
|
||||
abstract class Widget extends dart.core::Object implements dart.developer::_HasCreationLocation /*hasConstConstructor*/ {
|
||||
final field dart.developer::CreationLocation? dart.developer::_location;
|
||||
const constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = null}) → wid::Widget
|
||||
: super dart.core::Object::•(), wid::Widget::_location = $creationLocationd_0dea112b090073317d4
|
||||
;
|
||||
}
|
||||
class StandardWidget extends wid::Widget /*hasConstConstructor*/ {
|
||||
const constructor •({dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = null}) → wid::StandardWidget
|
||||
: super wid::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
const constructor named(dart.core::String name, {dart.developer::CreationLocation? $creationLocationd_0dea112b090073317d4 = null}) → wid::StandardWidget
|
||||
: super wid::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
|
||||
;
|
||||
static synthetic method _#new#tearOff() → wid::StandardWidget
|
||||
return new wid::StandardWidget::•($creationLocationd_0dea112b090073317d4: const dart.developer::CreationLocation::_(file: "org-dartlang-test:///widget.dart", line: 9, column: 9, name: "StandardWidget"));
|
||||
static synthetic method _#named#tearOff(dart.core::String name) → wid::StandardWidget
|
||||
return new wid::StandardWidget::named(name, $creationLocationd_0dea112b090073317d4: const dart.developer::CreationLocation::_(file: "org-dartlang-test:///widget.dart", line: 10, column: 9, name: "StandardWidget"));
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
# Reproduce a crash.
|
||||
|
||||
type: newworld
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
target: dartdevc # basically needed for widget creation to be run
|
||||
worlds:
|
||||
- entry: flutter_gallery/lib/main.dart
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Reproduce a crash.
|
||||
|
||||
type: newworld
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
target: vm
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Reproduce a crash.
|
||||
|
||||
type: newworld
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
target: vm
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
type: newworld
|
||||
target: dartdevc
|
||||
trackWidgetCreation: true
|
||||
trackCreationLocations: true
|
||||
worlds:
|
||||
- entry: main.dart
|
||||
sources:
|
||||
|
||||
@@ -102,7 +102,15 @@ final ArgParser summaryArgsParser = new ArgParser()
|
||||
..addFlag('reuse-compiler-result', defaultsTo: false)
|
||||
..addFlag('use-incremental-compiler', defaultsTo: false)
|
||||
..addOption('used-inputs')
|
||||
..addFlag('track-widget-creation', defaultsTo: false)
|
||||
..addFlag(
|
||||
'track-creation-locations',
|
||||
defaultsTo: false,
|
||||
aliases: [
|
||||
// TODO(http://dartbug.com/63225): Remove this once flutter is migrated
|
||||
// to the new flag.
|
||||
'track-widget-creation',
|
||||
],
|
||||
)
|
||||
..addFlag('include-unsupported-platform-library-stubs', defaultsTo: false)
|
||||
..addMultiOption(
|
||||
'enable-experiment',
|
||||
@@ -205,7 +213,7 @@ Future<ComputeKernelResult> computeKernel(
|
||||
if (summaryOnly && !summary) {
|
||||
throw new ArgumentError('--summary-only conflicts with --no-summary');
|
||||
}
|
||||
bool trackWidgetCreation = parsedArgs['track-widget-creation'] as bool;
|
||||
bool trackCreationLocations = parsedArgs['track-creation-locations'] as bool;
|
||||
bool includeUnsupportedPlatformLibraryStubs =
|
||||
parsedArgs['include-unsupported-platform-library-stubs'] as bool;
|
||||
|
||||
@@ -214,7 +222,7 @@ Future<ComputeKernelResult> computeKernel(
|
||||
String targetName =
|
||||
(parsedArgs['target'] as String?) ?? (summaryOnly ? 'ddc' : 'vm');
|
||||
TargetFlags targetFlags = new TargetFlags(
|
||||
trackWidgetCreation: trackWidgetCreation,
|
||||
trackCreationLocations: trackCreationLocations,
|
||||
includeUnsupportedPlatformLibraryStubs:
|
||||
includeUnsupportedPlatformLibraryStubs,
|
||||
);
|
||||
@@ -392,8 +400,8 @@ Future<ComputeKernelResult> computeKernel(
|
||||
previousState,
|
||||
{
|
||||
"target=$targetName",
|
||||
// trackWidgetCreation is in TargetFlags.
|
||||
"trackWidgetCreation=$trackWidgetCreation",
|
||||
// trackCreationLocations is in TargetFlags.
|
||||
"trackCreationLocations=$trackCreationLocations",
|
||||
// includeUnsupportedPlatformLibraryStubs is in TargetFlags.
|
||||
"includeUnsupportedPlatformLibraryStubs="
|
||||
"$includeUnsupportedPlatformLibraryStubs",
|
||||
|
||||
@@ -261,9 +261,16 @@ ArgParser argParser = new ArgParser(allowTrailingOptions: true)
|
||||
hide: true,
|
||||
)
|
||||
..addFlag(
|
||||
'track-widget-creation',
|
||||
help: 'Run a kernel transformer to track creation locations for widgets.',
|
||||
'track-creation-locations',
|
||||
help:
|
||||
'Run a kernel transformer to track creation locations for'
|
||||
' classes annotated with @pragma(\'track-creation-locations\').',
|
||||
defaultsTo: false,
|
||||
aliases: [
|
||||
// TODO(http://dartbug.com/63225): Remove this once flutter is migrated
|
||||
// to the new flag.
|
||||
'track-widget-creation',
|
||||
],
|
||||
)
|
||||
..addMultiOption(
|
||||
'delete-tostring-package-uri',
|
||||
@@ -800,7 +807,7 @@ class FrontendCompiler implements CompilerInterface {
|
||||
final bool minimalKernel = options['minimal-kernel'];
|
||||
compilerOptions.target = createFrontEndTarget(
|
||||
options['target'],
|
||||
trackWidgetCreation: options['track-widget-creation'],
|
||||
trackCreationLocations: options['track-creation-locations'],
|
||||
supportMirrors: options['support-mirrors'] ?? !(aot || minimalKernel),
|
||||
includeUnsupportedPlatformLibraryStubs:
|
||||
options['include-unsupported-platform-library-stubs'],
|
||||
|
||||
@@ -12,7 +12,7 @@ import '../verifier.dart';
|
||||
import 'changed_structure_notifier.dart';
|
||||
|
||||
class TargetFlags {
|
||||
final bool trackWidgetCreation;
|
||||
final bool trackCreationLocations;
|
||||
final bool supportMirrors;
|
||||
|
||||
/// Whether the backend expects closure contexts to be present in the AST.
|
||||
@@ -32,7 +32,7 @@ class TargetFlags {
|
||||
final bool includeUnsupportedPlatformLibraryStubs;
|
||||
|
||||
const TargetFlags({
|
||||
this.trackWidgetCreation = false,
|
||||
this.trackCreationLocations = false,
|
||||
this.supportMirrors = true,
|
||||
this.isClosureContextLoweringEnabled = false,
|
||||
this.constKeepLocalsIndicator,
|
||||
@@ -43,7 +43,7 @@ class TargetFlags {
|
||||
bool operator ==(other) {
|
||||
if (identical(this, other)) return true;
|
||||
return other is TargetFlags &&
|
||||
trackWidgetCreation == other.trackWidgetCreation &&
|
||||
trackCreationLocations == other.trackCreationLocations &&
|
||||
supportMirrors == other.supportMirrors &&
|
||||
includeUnsupportedPlatformLibraryStubs ==
|
||||
other.includeUnsupportedPlatformLibraryStubs &&
|
||||
@@ -53,7 +53,7 @@ class TargetFlags {
|
||||
@override
|
||||
int get hashCode {
|
||||
int hash = 485786;
|
||||
hash = 0x3fffffff & (hash * 31 + (hash ^ trackWidgetCreation.hashCode));
|
||||
hash = 0x3fffffff & (hash * 31 + (hash ^ trackCreationLocations.hashCode));
|
||||
hash = 0x3fffffff & (hash * 31 + (hash ^ supportMirrors.hashCode));
|
||||
hash =
|
||||
0x3fffffff &
|
||||
@@ -340,7 +340,11 @@ abstract class Target {
|
||||
/// This transformation is not applied when compiling full kernel programs to
|
||||
/// prevent affecting the internal invariants of the compiler and accidentally
|
||||
/// slowing down compilation.
|
||||
void performOutlineTransformations(Component component) {}
|
||||
void performOutlineTransformations(
|
||||
Component component, {
|
||||
List<Library>? libraries,
|
||||
ChangedStructureNotifier? changedStructureNotifier,
|
||||
}) {}
|
||||
|
||||
/// Perform target-specific operations on the [Component] storing the outlines
|
||||
/// when generating summaries.
|
||||
@@ -821,7 +825,7 @@ class TestTargetFlags extends TargetFlags {
|
||||
final Set<String> unsupportedDartLibraries;
|
||||
|
||||
const TestTargetFlags({
|
||||
bool trackWidgetCreation = false,
|
||||
bool trackCreationLocations = false,
|
||||
this.forceLateLoweringsForTesting,
|
||||
this.forceLateLoweringSentinelForTesting,
|
||||
this.forceStaticFieldLoweringForTesting,
|
||||
@@ -831,7 +835,7 @@ class TestTargetFlags extends TargetFlags {
|
||||
this.unsupportedDartLibraries = const {},
|
||||
bool isClosureContextLoweringEnabled = false,
|
||||
}) : super(
|
||||
trackWidgetCreation: trackWidgetCreation,
|
||||
trackCreationLocations: trackCreationLocations,
|
||||
isClosureContextLoweringEnabled: isClosureContextLoweringEnabled,
|
||||
);
|
||||
}
|
||||
@@ -1040,8 +1044,16 @@ class TargetWrapper extends Target {
|
||||
}
|
||||
|
||||
@override
|
||||
void performOutlineTransformations(Component component) {
|
||||
_target.performOutlineTransformations(component);
|
||||
void performOutlineTransformations(
|
||||
Component component, {
|
||||
List<Library>? libraries,
|
||||
ChangedStructureNotifier? changedStructureNotifier,
|
||||
}) {
|
||||
_target.performOutlineTransformations(
|
||||
component,
|
||||
libraries: libraries,
|
||||
changedStructureNotifier: changedStructureNotifier,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1131,10 +1143,10 @@ mixin SummaryMixin on Target {
|
||||
super.performOutlineComponentOperations(component);
|
||||
if (!excludeNonSources) return;
|
||||
|
||||
List<Library> libraries = new List.of(component.libraries);
|
||||
List<Library> componentLibraries = new List.of(component.libraries);
|
||||
component.libraries.clear();
|
||||
Set<Uri> include = sources.toSet();
|
||||
for (Library library in libraries) {
|
||||
for (Library library in componentLibraries) {
|
||||
if (include.contains(library.importUri)) {
|
||||
component.libraries.add(library);
|
||||
} else {
|
||||
|
||||
@@ -61,7 +61,6 @@ void _maybeAddCreationLocationArgument(
|
||||
Arguments arguments,
|
||||
FunctionNode function,
|
||||
Expression creationLocation,
|
||||
Class locationClass,
|
||||
) {
|
||||
if (_hasNamedArgument(arguments, _creationLocationParameterName)) {
|
||||
return;
|
||||
@@ -120,15 +119,6 @@ bool _maybeAddNamedParameter(
|
||||
/// 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 is-tests to determine whether Dart constructor calls are
|
||||
/// creating [Widget] objects.
|
||||
final Class _widgetClass;
|
||||
|
||||
/// 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
|
||||
@@ -151,13 +141,8 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
/// of the library.
|
||||
Library? _currentLibrary;
|
||||
|
||||
_WidgetCallSiteTransformer({
|
||||
required Class widgetClass,
|
||||
required Class locationClass,
|
||||
required WidgetCreatorTracker tracker,
|
||||
}) : _widgetClass = widgetClass,
|
||||
_locationClass = locationClass,
|
||||
_tracker = tracker;
|
||||
_WidgetCallSiteTransformer({required WidgetCreatorTracker tracker})
|
||||
: _tracker = tracker;
|
||||
|
||||
/// Builds a call to the const constructor of the _Location
|
||||
/// object specifying the location where a constructor call was made and
|
||||
@@ -169,7 +154,12 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
/// constructor call but it is convenient to bundle the location and names
|
||||
/// of the parameters passed in so that tools can show parameter locations
|
||||
/// without re-parsing the source code.
|
||||
ConstructorInvocation _constructLocation(Location location, {String? name}) {
|
||||
|
||||
ConstructorInvocation _constructLocation(
|
||||
Location location, {
|
||||
required Class locationClass,
|
||||
String? name,
|
||||
}) {
|
||||
final List<NamedExpression> arguments = <NamedExpression>[
|
||||
new NamedExpression('file', new StringLiteral(location.file.toString())),
|
||||
new NamedExpression('line', new IntLiteral(location.line)),
|
||||
@@ -178,7 +168,7 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
];
|
||||
|
||||
return new ConstructorInvocation(
|
||||
_locationClass.constructors.first,
|
||||
locationClass.constructors.first,
|
||||
new Arguments(<Expression>[], named: arguments),
|
||||
isConst: true,
|
||||
);
|
||||
@@ -210,10 +200,6 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
return node;
|
||||
}
|
||||
|
||||
bool _isSubclassOfWidget(Class clazz) {
|
||||
return _tracker._isSubclassOf(clazz, _widgetClass);
|
||||
}
|
||||
|
||||
bool _isWidgetFactory(Procedure node) {
|
||||
return node.isExtensionMember &&
|
||||
_hasNamedParameter(node.function, _creationLocationParameterName);
|
||||
@@ -225,7 +211,10 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
final Procedure target = node.target;
|
||||
if (target.isFactory) {
|
||||
final Class constructedClass = target.enclosingClass!;
|
||||
if (!_isSubclassOfWidget(constructedClass)) {
|
||||
final _TrackingClasses? tracking = _tracker._getTrackingClasses(
|
||||
constructedClass,
|
||||
);
|
||||
if (tracking == null) {
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -234,11 +223,16 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
target.function,
|
||||
constructedClass: constructedClass,
|
||||
isConst: node.isConst,
|
||||
locationClass: tracking.locationClass,
|
||||
);
|
||||
return node;
|
||||
}
|
||||
if (_isWidgetFactory(target)) {
|
||||
_addLocationArgument(node, target.function);
|
||||
if (_isWidgetFactory(target) && _tracker._locationClass != null) {
|
||||
_addLocationArgument(
|
||||
node,
|
||||
target.function,
|
||||
locationClass: _tracker._locationClass!,
|
||||
);
|
||||
return node;
|
||||
}
|
||||
return node;
|
||||
@@ -249,6 +243,7 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
FunctionNode function, {
|
||||
Class? constructedClass,
|
||||
bool isConst = false,
|
||||
required Class locationClass,
|
||||
}) {
|
||||
Expression? location = _currentExtensionFactoryLocationParameter;
|
||||
if (location == null ||
|
||||
@@ -261,14 +256,10 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
function,
|
||||
constructedClass,
|
||||
isConst: isConst,
|
||||
locationClass: locationClass,
|
||||
);
|
||||
}
|
||||
_maybeAddCreationLocationArgument(
|
||||
node.arguments,
|
||||
function,
|
||||
location,
|
||||
_locationClass,
|
||||
);
|
||||
_maybeAddCreationLocationArgument(node.arguments, function, location);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -277,7 +268,10 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
|
||||
final Constructor constructor = node.target;
|
||||
final Class constructedClass = constructor.enclosingClass;
|
||||
if (!_isSubclassOfWidget(constructedClass)) {
|
||||
final _TrackingClasses? tracking = _tracker._getTrackingClasses(
|
||||
constructedClass,
|
||||
);
|
||||
if (tracking == null) {
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -286,6 +280,7 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
constructor.function,
|
||||
constructedClass: constructedClass,
|
||||
isConst: node.isConst,
|
||||
locationClass: tracking.locationClass,
|
||||
);
|
||||
return node;
|
||||
}
|
||||
@@ -295,6 +290,7 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
FunctionNode function,
|
||||
Class? constructedClass, {
|
||||
bool isConst = false,
|
||||
required Class locationClass,
|
||||
}) {
|
||||
assert(constructedClass != null || !isConst);
|
||||
|
||||
@@ -302,9 +298,9 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
// argument to the factory constructor rather than the location
|
||||
if (constructedClass != null &&
|
||||
_currentFactory != null &&
|
||||
_tracker._isSubclassOf(
|
||||
_tracker._isSubclassWhere(
|
||||
constructedClass,
|
||||
_currentFactory!.enclosingClass!,
|
||||
(Class c) => c == _currentFactory!.enclosingClass!,
|
||||
) &&
|
||||
// If the constructor invocation is constant we cannot refer to the
|
||||
// location parameter of the surrounding factory since it isn't a
|
||||
@@ -319,8 +315,13 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
}
|
||||
}
|
||||
|
||||
if (node.location == null) {
|
||||
return new NullLiteral();
|
||||
}
|
||||
|
||||
return _constructLocation(
|
||||
node.location!,
|
||||
locationClass: locationClass,
|
||||
name:
|
||||
constructedClass?.name ??
|
||||
// For extension factory methods we use the name of the method.
|
||||
@@ -360,12 +361,20 @@ class _WidgetCallSiteTransformer extends Transformer {
|
||||
/// invocations within the method.
|
||||
class WidgetCreatorTracker {
|
||||
bool _foundClasses = false;
|
||||
late Class _widgetClass;
|
||||
late Class _locationClass;
|
||||
|
||||
/// Marker interface indicating that a private _location field is
|
||||
/// available.
|
||||
late Class _hasCreationLocationClass;
|
||||
/// The [Widget] class defined in the `package:flutter` library.
|
||||
///
|
||||
/// Used to perform is-tests to determine whether Dart constructor calls are
|
||||
/// creating [Widget] objects.
|
||||
Class? _widgetClass;
|
||||
|
||||
/// The _Location class defined in the `package:flutter` library.
|
||||
Class? _locationClass;
|
||||
|
||||
/// The _HasCreationLocation class defined in the `package:flutter` library.
|
||||
///
|
||||
/// Marker interface indicating that a private _location field is available.
|
||||
Class? _hasCreationLocationClass;
|
||||
|
||||
/// Annotation class used to mark an extension method as a "Widget factory".
|
||||
///
|
||||
@@ -374,20 +383,27 @@ class WidgetCreatorTracker {
|
||||
/// method.
|
||||
Class? _widgetFactoryClass;
|
||||
|
||||
void _resolveFlutterClasses(Iterable<Library> libraries) {
|
||||
/// The _HasCreationLocation class defined in the `dart:developer` library.
|
||||
Class? _developerHasCreationLocationClass;
|
||||
|
||||
/// The CreationLocation class defined in the `dart:developer` library.
|
||||
Class? _developerCreationLocationClass;
|
||||
|
||||
void _resolveWellKnownClasses(Iterable<Library> libraries) {
|
||||
// If the Widget or Debug location classes have been updated we need to get
|
||||
// the latest version
|
||||
bool foundWidgetClass = false;
|
||||
bool foundHasCreationLocationClass = false;
|
||||
bool foundLocationClass = false;
|
||||
|
||||
for (Library library in libraries) {
|
||||
final Uri importUri = library.importUri;
|
||||
|
||||
// Legacy Case: Search for hardcoded Flutter classes.
|
||||
// TODO(http://dartbug.com/63225): Remove this once Flutter is migrated
|
||||
// to the new API.
|
||||
if (importUri.isScheme('package')) {
|
||||
if (importUri.path == 'flutter/src/widgets/framework.dart') {
|
||||
for (Class class_ in library.classes) {
|
||||
if (class_.name == 'Widget') {
|
||||
_widgetClass = class_;
|
||||
foundWidgetClass = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -395,10 +411,8 @@ class WidgetCreatorTracker {
|
||||
for (Class class_ in library.classes) {
|
||||
if (class_.name == '_HasCreationLocation') {
|
||||
_hasCreationLocationClass = class_;
|
||||
foundHasCreationLocationClass = true;
|
||||
} else if (class_.name == '_Location') {
|
||||
_locationClass = class_;
|
||||
foundLocationClass = true;
|
||||
} else if (class_.name == '_WidgetFactory') {
|
||||
_widgetFactoryClass = class_;
|
||||
}
|
||||
@@ -406,43 +420,62 @@ class WidgetCreatorTracker {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New Case: Search for classes in `dart:developer`
|
||||
if (importUri.isScheme('dart') && importUri.path == 'developer') {
|
||||
for (Class class_ in library.classes) {
|
||||
if (class_.name == '_HasCreationLocation') {
|
||||
_developerHasCreationLocationClass = class_;
|
||||
} else if (class_.name == 'CreationLocation') {
|
||||
_developerCreationLocationClass = class_;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO(johnniwinther): Require the [_widgetFactoryClass] once the
|
||||
// `widgetFactory` is stable in flutter.
|
||||
_foundClasses =
|
||||
foundWidgetClass && foundHasCreationLocationClass && foundLocationClass;
|
||||
(_widgetClass != null &&
|
||||
_hasCreationLocationClass != null &&
|
||||
_locationClass != null) ||
|
||||
(_developerHasCreationLocationClass != null &&
|
||||
_developerCreationLocationClass != null);
|
||||
}
|
||||
|
||||
/// Modify [clazz] to add a field named [_locationFieldName] that is the
|
||||
/// first parameter of all constructors of the class.
|
||||
/// Modify [clazz] to add the location field that is
|
||||
/// the first parameter of all constructors of the class.
|
||||
///
|
||||
/// This method should only be called for classes that implement but do not
|
||||
/// extend [Widget].
|
||||
void _transformClassImplementingWidget(
|
||||
/// extend the tracking base class.
|
||||
void _transformClassImplementingTrackingClass(
|
||||
Class clazz,
|
||||
_TrackingClasses tracking,
|
||||
ChangedStructureNotifier? changedStructureNotifier,
|
||||
) {
|
||||
if (clazz.fields.any(
|
||||
(Field field) => field.name.text == _locationFieldName,
|
||||
(Field field) => field.name.text == tracking.locationFieldName,
|
||||
)) {
|
||||
// This class has already been transformed. Skip
|
||||
return;
|
||||
}
|
||||
clazz.implementedTypes.add(
|
||||
new Supertype(_hasCreationLocationClass, <DartType>[]),
|
||||
new Supertype(tracking.hasCreationLocationClass, <DartType>[]),
|
||||
);
|
||||
changedStructureNotifier?.registerClassHierarchyChange(clazz);
|
||||
|
||||
// We intentionally use the library context of the _HasCreationLocation
|
||||
// class for the private field even if [clazz] is in a different library
|
||||
// so that all classes implementing Widget behave consistently.
|
||||
// so that all classes implementing the tracking class behave consistently.
|
||||
final Name fieldName = new Name(
|
||||
_locationFieldName,
|
||||
_hasCreationLocationClass.enclosingLibrary,
|
||||
tracking.locationFieldName,
|
||||
tracking.hasCreationLocationClass.enclosingLibrary,
|
||||
);
|
||||
final Field locationField = new Field.immutable(
|
||||
fieldName,
|
||||
type: new InterfaceType(_locationClass, clazz.enclosingLibrary.nullable),
|
||||
type: new InterfaceType(
|
||||
tracking.locationClass,
|
||||
clazz.enclosingLibrary.nullable,
|
||||
),
|
||||
isFinal: true,
|
||||
fieldReference: clazz.reference.canonicalName
|
||||
?.getChildFromFieldWithName(fieldName)
|
||||
@@ -470,7 +503,7 @@ class WidgetCreatorTracker {
|
||||
final VariableDeclaration variable = new VariableDeclaration(
|
||||
_creationLocationParameterName,
|
||||
type: new InterfaceType(
|
||||
_locationClass,
|
||||
tracking.locationClass,
|
||||
clazz.enclosingLibrary.nullable,
|
||||
),
|
||||
initializer: new NullLiteral(),
|
||||
@@ -492,7 +525,6 @@ class WidgetCreatorTracker {
|
||||
initializer.arguments,
|
||||
initializer.target.function,
|
||||
new VariableGet(variable),
|
||||
_locationClass,
|
||||
);
|
||||
hasRedirectingInitializer = true;
|
||||
break;
|
||||
@@ -512,7 +544,7 @@ class WidgetCreatorTracker {
|
||||
// constructor.initializers.add(new AssertInitializer(
|
||||
// new AssertStatement(
|
||||
// new IsExpression(
|
||||
// new VariableGet(variable), _locationClass.thisType),
|
||||
// new VariableGet(variable), tracking.locationClass.thisType),
|
||||
// conditionStartOffset: constructor.fileOffset,
|
||||
// conditionEndOffset: constructor.fileOffset,
|
||||
// )));
|
||||
@@ -525,7 +557,7 @@ class WidgetCreatorTracker {
|
||||
|
||||
/// Transform the given [libraries].
|
||||
///
|
||||
/// The libraries from [module] is searched for the Widget class,
|
||||
/// The [moduleLibraries] are searched for the Widget 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
|
||||
@@ -537,18 +569,18 @@ class WidgetCreatorTracker {
|
||||
/// compilation where the class hierarchy is kept between compiles and thus
|
||||
/// has to be kept up to date.
|
||||
void transform(
|
||||
Component module,
|
||||
List<Library> libraries,
|
||||
List<Library> moduleLibraries,
|
||||
ChangedStructureNotifier? changedStructureNotifier,
|
||||
) {
|
||||
if (libraries.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
_resolveFlutterClasses(module.libraries);
|
||||
_resolveWellKnownClasses(moduleLibraries);
|
||||
|
||||
if (!_foundClasses) {
|
||||
// This application doesn't actually use the package:flutter library.
|
||||
// Neither package:flutter nor dart:developer tracking classes found.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -579,11 +611,7 @@ class WidgetCreatorTracker {
|
||||
|
||||
// Transform call sites to pass the location parameter.
|
||||
final _WidgetCallSiteTransformer callsiteTransformer =
|
||||
new _WidgetCallSiteTransformer(
|
||||
widgetClass: _widgetClass,
|
||||
locationClass: _locationClass,
|
||||
tracker: this,
|
||||
);
|
||||
new _WidgetCallSiteTransformer(tracker: this);
|
||||
|
||||
for (Library library in libraries) {
|
||||
callsiteTransformer.enterLibrary(library);
|
||||
@@ -592,26 +620,110 @@ class WidgetCreatorTracker {
|
||||
}
|
||||
}
|
||||
|
||||
bool _isSubclassOfWidget(Class clazz) => _isSubclassOf(clazz, _widgetClass);
|
||||
_TrackingClasses? _getTrackingClasses(Class clazz) {
|
||||
// Legacy Case: Check for widget class.
|
||||
if (_isSubclassOfWidget(clazz)) {
|
||||
if (_hasCreationLocationClass != null && _locationClass != null) {
|
||||
return new _TrackingClasses(
|
||||
hasCreationLocationClass: _hasCreationLocationClass!,
|
||||
locationClass: _locationClass!,
|
||||
locationFieldName: _locationFieldName,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool _isSubclassOf(Class a, Class b) {
|
||||
// New Case: Check for 'pragma('track-creation-locations')' annotation.
|
||||
if (_hasTrackCreationLocationsPragmaAnnotation(clazz)) {
|
||||
if (_developerHasCreationLocationClass != null &&
|
||||
_developerCreationLocationClass != null) {
|
||||
return new _TrackingClasses(
|
||||
hasCreationLocationClass: _developerHasCreationLocationClass!,
|
||||
locationClass: _developerCreationLocationClass!,
|
||||
locationFieldName: _locationFieldName,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
bool _isSubclassOfWidget(Class clazz) {
|
||||
if (_widgetClass == null) return false;
|
||||
return _isSubclassWhere(clazz, (Class c) => c == _widgetClass);
|
||||
}
|
||||
|
||||
bool _hasTrackCreationLocationsPragmaAnnotation(Class clazz) {
|
||||
if (_developerHasCreationLocationClass == null) return false;
|
||||
return _isSubclassWhere(clazz, (Class c) {
|
||||
for (Expression annotation in c.annotations) {
|
||||
// Case before constant evaluation (newly compiled modules).
|
||||
if (annotation is RedirectingFactoryInvocation) {
|
||||
final expression = annotation.expression;
|
||||
|
||||
if (expression is ConstructorInvocation) {
|
||||
final Class enclosingClass = expression.target.enclosingClass;
|
||||
|
||||
if (enclosingClass.name == 'pragma' &&
|
||||
enclosingClass.enclosingLibrary.importUri.toString() ==
|
||||
'dart:core') {
|
||||
if (expression.arguments.positional.isNotEmpty) {
|
||||
final Expression firstArg =
|
||||
expression.arguments.positional.first;
|
||||
if (firstArg is StringLiteral &&
|
||||
firstArg.value == 'track-creation-locations') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Case after constant evaluation (incremental or modular compilation).
|
||||
if (annotation case ConstantExpression(
|
||||
constant: final InstanceConstant constant,
|
||||
)) {
|
||||
final Class enclosingClass = constant.classNode;
|
||||
|
||||
if (enclosingClass.name == 'pragma' &&
|
||||
enclosingClass.enclosingLibrary.importUri.toString() ==
|
||||
'dart:core') {
|
||||
for (final Constant value in constant.fieldValues.values) {
|
||||
if (value case StringConstant(
|
||||
value: 'track-creation-locations',
|
||||
)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
bool _isSubclassWhere(Class a, bool Function(Class b) predicate) {
|
||||
// TODO(askesc): Cache results.
|
||||
// TODO(askesc): Test for subtype rather than subclass.
|
||||
Class? current = a;
|
||||
while (current != null) {
|
||||
if (current == b) return true;
|
||||
if (predicate(current)) return true;
|
||||
current = current.superclass;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _hasWidgetFactoryAnnotation(Procedure node) =>
|
||||
_isAnnotatedWithNamedValueOfType(node, _widgetFactoryClass!);
|
||||
_isAnnotatedWithNamedValueOfType(
|
||||
node,
|
||||
_widgetFactoryClass,
|
||||
_widgetFactoryClass,
|
||||
);
|
||||
|
||||
bool _isAnnotatedWithNamedValueOfType(
|
||||
Annotatable node,
|
||||
Class annotationClass,
|
||||
Class? annotationClass,
|
||||
Class? typeClass,
|
||||
) {
|
||||
if (annotationClass == null || typeClass == null) return false;
|
||||
return node.annotations.any((annotation) {
|
||||
if (annotation is! StaticGet) {
|
||||
return false;
|
||||
@@ -627,7 +739,7 @@ class WidgetCreatorTracker {
|
||||
if (type.nullability == Nullability.nullable) {
|
||||
return false;
|
||||
}
|
||||
return type.classNode == _widgetFactoryClass;
|
||||
return type.classNode == typeClass;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -637,7 +749,8 @@ class WidgetCreatorTracker {
|
||||
Class clazz,
|
||||
ChangedStructureNotifier? changedStructureNotifier,
|
||||
) {
|
||||
if (!_isSubclassOfWidget(clazz) ||
|
||||
final _TrackingClasses? tracking = _getTrackingClasses(clazz);
|
||||
if (tracking == null ||
|
||||
!librariesToBeTransformed.contains(clazz.enclosingLibrary) ||
|
||||
!transformedClasses.add(clazz)) {
|
||||
return;
|
||||
@@ -661,7 +774,7 @@ class WidgetCreatorTracker {
|
||||
new VariableDeclaration(
|
||||
_creationLocationParameterName,
|
||||
type: new InterfaceType(
|
||||
_locationClass,
|
||||
tracking.locationClass,
|
||||
clazz.enclosingLibrary.nullable,
|
||||
),
|
||||
initializer: new NullLiteral(),
|
||||
@@ -672,8 +785,14 @@ class WidgetCreatorTracker {
|
||||
|
||||
// Handle the widget class and classes that implement but do not extend the
|
||||
// widget class.
|
||||
if (!_isSubclassOfWidget(clazz.superclass!)) {
|
||||
_transformClassImplementingWidget(clazz, changedStructureNotifier);
|
||||
if (clazz.superclass == null ||
|
||||
_getTrackingClasses(clazz.superclass!)?.hasCreationLocationClass !=
|
||||
tracking.hasCreationLocationClass) {
|
||||
_transformClassImplementingTrackingClass(
|
||||
clazz,
|
||||
tracking,
|
||||
changedStructureNotifier,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -688,7 +807,7 @@ class WidgetCreatorTracker {
|
||||
final VariableDeclaration variable = new VariableDeclaration(
|
||||
_creationLocationParameterName,
|
||||
type: new InterfaceType(
|
||||
_locationClass,
|
||||
tracking.locationClass,
|
||||
clazz.enclosingLibrary.nullable,
|
||||
),
|
||||
initializer: new NullLiteral(),
|
||||
@@ -717,16 +836,17 @@ class WidgetCreatorTracker {
|
||||
initializer.arguments,
|
||||
initializer.target.function,
|
||||
new VariableGet(variable),
|
||||
_locationClass,
|
||||
);
|
||||
} else if (initializer is SuperInitializer &&
|
||||
_isSubclassOfWidget(initializer.target.enclosingClass)) {
|
||||
_maybeAddCreationLocationArgument(
|
||||
initializer.arguments,
|
||||
initializer.target.function,
|
||||
new VariableGet(variable),
|
||||
_locationClass,
|
||||
);
|
||||
} else if (initializer is SuperInitializer) {
|
||||
final Class superclass = initializer.target.enclosingClass;
|
||||
if (_getTrackingClasses(superclass)?.hasCreationLocationClass ==
|
||||
tracking.hasCreationLocationClass) {
|
||||
_maybeAddCreationLocationArgument(
|
||||
initializer.arguments,
|
||||
initializer.target.function,
|
||||
new VariableGet(variable),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -761,7 +881,7 @@ class WidgetCreatorTracker {
|
||||
new VariableDeclaration(
|
||||
_creationLocationParameterName,
|
||||
type: new InterfaceType(
|
||||
_locationClass,
|
||||
_locationClass!,
|
||||
extension.enclosingLibrary.nullable,
|
||||
),
|
||||
initializer: new NullLiteral(),
|
||||
@@ -775,7 +895,7 @@ class WidgetCreatorTracker {
|
||||
new VariableDeclaration(
|
||||
_creationLocationParameterName,
|
||||
type: new InterfaceType(
|
||||
_locationClass,
|
||||
_locationClass!,
|
||||
extension.enclosingLibrary.nullable,
|
||||
),
|
||||
initializer: new NullLiteral(),
|
||||
@@ -785,3 +905,17 @@ class WidgetCreatorTracker {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds the set of creation location classes, either
|
||||
/// from `package:flutter` or `dart:developer`.
|
||||
class _TrackingClasses {
|
||||
final Class hasCreationLocationClass;
|
||||
final Class locationClass;
|
||||
final String locationFieldName;
|
||||
|
||||
_TrackingClasses({
|
||||
required this.hasCreationLocationClass,
|
||||
required this.locationClass,
|
||||
required this.locationFieldName,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
import 'package:kernel/ast.dart';
|
||||
import 'package:kernel/transformations/track_widget_constructor_locations.dart';
|
||||
|
||||
void main() {
|
||||
final Uri developerUri = Uri.parse('dart:developer');
|
||||
final Library developerLib = new Library(developerUri, fileUri: developerUri);
|
||||
|
||||
final Class hasCreationLocationClass = new Class(
|
||||
name: '_HasCreationLocation',
|
||||
isAbstract: true,
|
||||
fileUri: developerUri,
|
||||
);
|
||||
developerLib.addClass(hasCreationLocationClass);
|
||||
|
||||
final Class creationLocationClass = new Class(
|
||||
name: 'CreationLocation',
|
||||
fileUri: developerUri,
|
||||
);
|
||||
final Constructor creationLocationConstructor = new Constructor(
|
||||
new FunctionNode(
|
||||
null,
|
||||
namedParameters: [
|
||||
new VariableDeclaration('file', type: const DynamicType()),
|
||||
new VariableDeclaration('line', type: const DynamicType()),
|
||||
new VariableDeclaration('column', type: const DynamicType()),
|
||||
new VariableDeclaration('name', type: const DynamicType()),
|
||||
],
|
||||
),
|
||||
name: new Name('_', developerLib),
|
||||
fileUri: developerUri,
|
||||
);
|
||||
creationLocationClass.addConstructor(creationLocationConstructor);
|
||||
developerLib.addClass(creationLocationClass);
|
||||
|
||||
final Uri coreUri = Uri.parse('dart:core');
|
||||
final Library coreLib = new Library(coreUri, fileUri: coreUri);
|
||||
final Class pragmaClass = new Class(name: 'pragma', fileUri: coreUri);
|
||||
coreLib.addClass(pragmaClass);
|
||||
final Field pragmaNameField = new Field.immutable(
|
||||
new Name('name'),
|
||||
fileUri: coreUri,
|
||||
);
|
||||
pragmaClass.addField(pragmaNameField);
|
||||
|
||||
final Uri testUri = Uri.parse('package:test/test.dart');
|
||||
final Library testLib = new Library(testUri, fileUri: testUri);
|
||||
|
||||
final Class myWidgetClass = new Class(name: 'MyWidget', fileUri: testUri);
|
||||
myWidgetClass.addAnnotation(
|
||||
new ConstantExpression(
|
||||
new InstanceConstant(
|
||||
pragmaClass.reference,
|
||||
<DartType>[],
|
||||
<Reference, Constant>{
|
||||
pragmaNameField.fieldReference: new StringConstant(
|
||||
'track-creation-locations',
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
myWidgetClass.addConstructor(
|
||||
new Constructor(
|
||||
new FunctionNode(new Block([])),
|
||||
name: new Name(''),
|
||||
fileUri: testUri,
|
||||
),
|
||||
);
|
||||
testLib.addClass(myWidgetClass);
|
||||
|
||||
const int fileOffset = 100;
|
||||
final Procedure mainProcedure = new Procedure(
|
||||
new Name('main'),
|
||||
ProcedureKind.Method,
|
||||
new FunctionNode(
|
||||
new Block([
|
||||
new ExpressionStatement(
|
||||
new ConstructorInvocation(
|
||||
myWidgetClass.constructors.first,
|
||||
new Arguments([]),
|
||||
)..fileOffset = fileOffset,
|
||||
),
|
||||
]),
|
||||
),
|
||||
isStatic: true,
|
||||
fileUri: testUri,
|
||||
);
|
||||
testLib.addProcedure(mainProcedure);
|
||||
|
||||
final WidgetCreatorTracker tracker = new WidgetCreatorTracker();
|
||||
tracker.transform([testLib], [developerLib, testLib], null);
|
||||
|
||||
// Verification
|
||||
Expect.isTrue(
|
||||
myWidgetClass.implementedTypes.any(
|
||||
(s) => s.classNode == hasCreationLocationClass,
|
||||
),
|
||||
);
|
||||
Expect.isTrue(myWidgetClass.fields.any((f) => f.name.text == '_location'));
|
||||
|
||||
final Constructor constructor = myWidgetClass.constructors.first;
|
||||
const String creationLocationPrefix = r'$creationLocation';
|
||||
Expect.isTrue(
|
||||
constructor.function.namedParameters.any(
|
||||
(p) => p.name!.startsWith(creationLocationPrefix),
|
||||
),
|
||||
);
|
||||
|
||||
final Block body = mainProcedure.function.body as Block;
|
||||
final ExpressionStatement stmt = body.statements.first as ExpressionStatement;
|
||||
final ConstructorInvocation invocation =
|
||||
stmt.expression as ConstructorInvocation;
|
||||
Expect.isTrue(
|
||||
invocation.arguments.named.any(
|
||||
(n) => n.name.startsWith(creationLocationPrefix),
|
||||
),
|
||||
);
|
||||
|
||||
final NamedExpression namedArg = invocation.arguments.named.firstWhere(
|
||||
(n) => n.name.startsWith(creationLocationPrefix),
|
||||
);
|
||||
Expect.isTrue(namedArg.value is ConstructorInvocation);
|
||||
final ConstructorInvocation locInvocation =
|
||||
namedArg.value as ConstructorInvocation;
|
||||
Expect.equals(creationLocationClass, locInvocation.target.enclosingClass);
|
||||
}
|
||||
@@ -114,9 +114,14 @@ final ArgParser _argParser = ArgParser(allowTrailingOptions: true)
|
||||
help: 'Print this help message.',
|
||||
)
|
||||
..addFlag(
|
||||
'track-widget-creation',
|
||||
'track-creation-locations',
|
||||
help: 'Run a kernel transformer to track creation locations for widgets.',
|
||||
defaultsTo: false,
|
||||
aliases: [
|
||||
// TODO(http://dartbug.com/63225): Remove this once flutter is migrated
|
||||
// to the new flag.
|
||||
'track-widget-creation',
|
||||
],
|
||||
)
|
||||
..addOption(
|
||||
'invocation-modes',
|
||||
@@ -180,7 +185,7 @@ Future<int> runCompilerWithCommandLineArguments(List<String> arguments) async {
|
||||
final String? importDill = options['import-dill'];
|
||||
final String messageVerbosity = options['verbosity'];
|
||||
final String cfeInvocationModes = options['invocation-modes'];
|
||||
final bool trackWidgetCreation = options['track-widget-creation'];
|
||||
final bool trackCreationLocations = options['track-creation-locations'];
|
||||
|
||||
final TargetCPU targetCPU = TargetCPU.fromName(options['target-arch']);
|
||||
final ImageFormat imageFormat = ImageFormat.fromName(options['image-format']);
|
||||
@@ -225,7 +230,7 @@ Future<int> runCompilerWithCommandLineArguments(List<String> arguments) async {
|
||||
..verbosity = verbosity
|
||||
..target = createFrontEndTarget(
|
||||
targetName,
|
||||
trackWidgetCreation: trackWidgetCreation,
|
||||
trackCreationLocations: trackCreationLocations,
|
||||
supportMirrors: false,
|
||||
isClosureContextLoweringEnabled: false,
|
||||
);
|
||||
|
||||
@@ -243,9 +243,14 @@ void declareCompilerOptions(ArgParser args) {
|
||||
help: 'Print this help message.',
|
||||
);
|
||||
args.addFlag(
|
||||
'track-widget-creation',
|
||||
'track-creation-locations',
|
||||
help: 'Run a kernel transformer to track creation locations for widgets.',
|
||||
defaultsTo: false,
|
||||
aliases: [
|
||||
// TODO(http://dartbug.com/63225): Remove this once flutter is migrated
|
||||
// to the new flag.
|
||||
'track-widget-creation',
|
||||
],
|
||||
);
|
||||
args.addMultiOption(
|
||||
'delete-tostring-package-uri',
|
||||
@@ -435,7 +440,7 @@ Future<int> runCompiler(ArgResults options, String usage) async {
|
||||
|
||||
compilerOptions.target = createFrontEndTarget(
|
||||
targetName,
|
||||
trackWidgetCreation: options['track-widget-creation'],
|
||||
trackCreationLocations: options['track-creation-locations'],
|
||||
supportMirrors: supportMirrors ?? !(aot || minimalKernel),
|
||||
constKeepLocalsIndicator: !(aot || minimalKernel),
|
||||
);
|
||||
@@ -1014,7 +1019,7 @@ bool parseCommandLineDefines(
|
||||
/// Create front-end target with given name.
|
||||
Target? createFrontEndTarget(
|
||||
String targetName, {
|
||||
bool trackWidgetCreation = false,
|
||||
bool trackCreationLocations = false,
|
||||
bool supportMirrors = true,
|
||||
bool includeUnsupportedPlatformLibraryStubs = false,
|
||||
bool? constKeepLocalsIndicator,
|
||||
@@ -1024,7 +1029,7 @@ Target? createFrontEndTarget(
|
||||
installAdditionalTargets();
|
||||
|
||||
final TargetFlags targetFlags = new TargetFlags(
|
||||
trackWidgetCreation: trackWidgetCreation,
|
||||
trackCreationLocations: trackCreationLocations,
|
||||
supportMirrors: supportMirrors,
|
||||
includeUnsupportedPlatformLibraryStubs:
|
||||
includeUnsupportedPlatformLibraryStubs,
|
||||
|
||||
@@ -2,18 +2,12 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:kernel/ast.dart' show Component, Library;
|
||||
import 'package:kernel/core_types.dart' show CoreTypes;
|
||||
import 'package:kernel/target/changed_structure_notifier.dart';
|
||||
import 'package:kernel/target/targets.dart';
|
||||
import 'package:kernel/transformations/track_widget_constructor_locations.dart';
|
||||
import 'package:vm/modular/target/vm.dart' show VmTarget;
|
||||
|
||||
class FlutterTarget extends VmTarget {
|
||||
FlutterTarget(TargetFlags flags) : super(flags);
|
||||
|
||||
late final WidgetCreatorTracker _widgetTracker = WidgetCreatorTracker();
|
||||
|
||||
@override
|
||||
String get name => 'flutter';
|
||||
|
||||
@@ -51,26 +45,4 @@ class FlutterTarget extends VmTarget {
|
||||
@override
|
||||
DartLibrarySupport get dartLibrarySupport =>
|
||||
const CustomizedDartLibrarySupport(unsupported: {'mirrors'});
|
||||
|
||||
@override
|
||||
void performPreConstantEvaluationTransformations(
|
||||
Component component,
|
||||
CoreTypes coreTypes,
|
||||
List<Library> libraries,
|
||||
DiagnosticReporter diagnosticReporter, {
|
||||
void Function(String msg)? logger,
|
||||
ChangedStructureNotifier? changedStructureNotifier,
|
||||
}) {
|
||||
super.performPreConstantEvaluationTransformations(
|
||||
component,
|
||||
coreTypes,
|
||||
libraries,
|
||||
diagnosticReporter,
|
||||
logger: logger,
|
||||
changedStructureNotifier: changedStructureNotifier,
|
||||
);
|
||||
if (flags.trackWidgetCreation) {
|
||||
_widgetTracker.transform(component, libraries, changedStructureNotifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:kernel/core_types.dart';
|
||||
import 'package:kernel/reference_from_index.dart';
|
||||
import 'package:kernel/target/changed_structure_notifier.dart';
|
||||
import 'package:kernel/target/targets.dart';
|
||||
import 'package:kernel/transformations/track_widget_constructor_locations.dart';
|
||||
|
||||
import '../transformations/call_site_annotator.dart' as callSiteAnnotator;
|
||||
import '../transformations/deeply_immutable.dart' as deeply_immutable;
|
||||
@@ -135,6 +136,8 @@ class VmTarget extends Target {
|
||||
..parent = host;
|
||||
}
|
||||
|
||||
late final WidgetCreatorTracker _widgetTracker = WidgetCreatorTracker();
|
||||
|
||||
@override
|
||||
void performPreConstantEvaluationTransformations(
|
||||
Component component,
|
||||
@@ -153,6 +156,14 @@ class VmTarget extends Target {
|
||||
changedStructureNotifier: changedStructureNotifier,
|
||||
);
|
||||
_patchVmConstants(coreTypes);
|
||||
|
||||
if (flags.trackCreationLocations) {
|
||||
_widgetTracker.transform(
|
||||
libraries,
|
||||
component.libraries,
|
||||
changedStructureNotifier,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -23,6 +23,7 @@ These pragmas are part of the VM's API and are safe for use in external code.
|
||||
| `vm:align-loops` | Tells compiler to align all loop headers inside the function to an architecture specific boundary: currently 32 bytes on X64 and ARM64 (except Apple Silicon, which explicitly discourages aligning branch targets) |
|
||||
| `vm:no-sanitize-thread` | Disable ThreadSanitizer instrumentation |
|
||||
| `external-effect` | Declares a static method which will be treated as live code when performing any analysis of the program. The call itself (and its arguments) are then dropped from the running program.
|
||||
| `track-creation-locations` | Marks a class, instances of which should have their creation locations tracked. Tracked creation locations are stored in a private field of the class and can be accessed through the `CreationLocation.of(object)` method in `dart:developer`. |
|
||||
|
||||
## Unsafe pragmas for general use
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
part of dart.developer;
|
||||
|
||||
/// Holds the source code location where an object was created, when its class
|
||||
/// was annotated with `@pragma('track-creation-locations')`.
|
||||
///
|
||||
/// When a class definition is annotated with `@pragma('track-creation-locations')`,
|
||||
/// the Dart compiler injects the call-site location into any invocation of that
|
||||
/// class's or any subclass's constructors and stores it in the created object.
|
||||
///
|
||||
/// The location of such an object can be read by calling [CreationLocation.of]
|
||||
/// with the object as the argument.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```dart
|
||||
/// import 'dart:developer';
|
||||
///
|
||||
/// // Marks this and any subclass to have their constructor call-sites tracked.
|
||||
/// @pragma('track-creation-locations')
|
||||
/// class TargetClass {
|
||||
/// TargetClass();
|
||||
/// }
|
||||
///
|
||||
/// void main() {
|
||||
/// // The source-code location of this constructor call is injected into the object.
|
||||
/// final instance = TargetClass();
|
||||
///
|
||||
/// final location = CreationLocation.of(instance);
|
||||
/// print(location); // Will print the current file path, line 11, column 20
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## Limitations
|
||||
///
|
||||
/// The compiler transformation relies on injecting a named parameter into the
|
||||
/// target class's constructors. Since Dart semantics do not permit a function
|
||||
/// to have both optional positional parameters and named parameters simultaneously,
|
||||
/// this transformation **will silently skip** any constructor that declares optional
|
||||
/// positional parameters. Calling [CreationLocation.of] on an object whose
|
||||
/// constructor was skipped, will return `null`.
|
||||
final class CreationLocation {
|
||||
/// Returns the creation location of [object].
|
||||
///
|
||||
/// The provided object must be an instance of a class annotated with
|
||||
/// `@pragma('track-creation-locations')`.
|
||||
static CreationLocation? of(Object? object) {
|
||||
if (object is _HasCreationLocation) {
|
||||
return object._location;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const CreationLocation._({
|
||||
required this.file,
|
||||
required this.line,
|
||||
required this.column,
|
||||
this.name,
|
||||
});
|
||||
|
||||
/// 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;
|
||||
|
||||
/// JSON representation of this location.
|
||||
Map<String, Object?> toJsonMap() {
|
||||
return <String, Object?>{
|
||||
'file': file,
|
||||
'line': line,
|
||||
'column': column,
|
||||
'name': name,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => <String>[?name, file, '$line', '$column'].join(':');
|
||||
}
|
||||
|
||||
/// Interface for classes that track the source code location their
|
||||
/// constructor was called from.
|
||||
abstract interface class _HasCreationLocation {
|
||||
/// The location where the constructor was called.
|
||||
CreationLocation? _location;
|
||||
}
|
||||
@@ -79,6 +79,7 @@ import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
import 'dart:isolate' show Isolate, RawReceivePort, SendPort;
|
||||
|
||||
part 'creation_tracking.dart';
|
||||
part 'extension.dart';
|
||||
part 'http_profiling.dart';
|
||||
part 'profiler.dart';
|
||||
|
||||
@@ -6,6 +6,7 @@ developer_sdk_sources = [
|
||||
"developer.dart",
|
||||
|
||||
# The above file needs to be first if additional parts are added to the lib.
|
||||
"creation_tracking.dart",
|
||||
"extension.dart",
|
||||
"profiler.dart",
|
||||
"service.dart",
|
||||
|
||||
Reference in New Issue
Block a user