From 0d052e396986d288ea8d4c9f329ab5b120a6c855 Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Mon, 24 Nov 2025 05:04:03 -0800 Subject: [PATCH] [deps] Roll dart-lang/native This roll moves `package:record_use` to the dart-lang/native repo. Change-Id: I31183dc8b72272d7e94ed3031ca0b8bfca583e0d Cq-Include-Trybots: luci.dart.try:pkg-linux-debug-try,pkg-linux-release-arm64-try,pkg-linux-release-try,pkg-mac-release-arm64-try,pkg-mac-release-try,pkg-win-release-arm64-try,pkg-win-release-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/463662 Commit-Queue: Daco Harkes Reviewed-by: Michael Goderbauer --- DEPS | 2 +- pkg/dartdev/test/native_assets/helpers.dart | 8 +- pkg/record_use/CHANGELOG.md | 30 -- pkg/record_use/LICENSE | 27 -- pkg/record_use/OWNERS | 5 - pkg/record_use/README.md | 117 ------- pkg/record_use/analysis_options.yaml | 4 - .../example/record_use_example.dart | 17 - pkg/record_use/lib/record_use.dart | 8 - pkg/record_use/lib/record_use_internal.dart | 25 -- pkg/record_use/lib/src/constant.dart | 262 -------------- pkg/record_use/lib/src/definition.dart | 42 --- pkg/record_use/lib/src/helper.dart | 9 - pkg/record_use/lib/src/identifier.dart | 68 ---- pkg/record_use/lib/src/location.dart | 44 --- pkg/record_use/lib/src/metadata.dart | 41 --- pkg/record_use/lib/src/record_use.dart | 140 -------- .../lib/src/recorded_usage_from_file.dart | 13 - pkg/record_use/lib/src/recordings.dart | 259 -------------- pkg/record_use/lib/src/reference.dart | 198 ----------- pkg/record_use/lib/src/version.dart | 7 - pkg/record_use/pubspec.yaml | 19 - pkg/record_use/test/storage_test.dart | 42 --- pkg/record_use/test/test_data.dart | 326 ------------------ pkg/record_use/test/usage_test.dart | 127 ------- .../test_data/drop_data_asset/.gitignore | 1 - .../test_data/drop_data_asset/README.md | 17 - .../test_data/drop_data_asset/assets/add.txt | 1 - .../drop_data_asset/assets/double.txt | 1 - .../drop_data_asset/assets/multiply.txt | 1 - .../drop_data_asset/assets/square.txt | 1 - .../bin/drop_data_asset_calls.dart | 9 - .../bin/drop_data_asset_instances.dart | 9 - .../test_data/drop_data_asset/hook/build.dart | 24 -- .../test_data/drop_data_asset/hook/link.dart | 79 ----- .../drop_data_asset/lib/drop_data_asset.dart | 5 - .../lib/src/drop_data_asset.dart | 26 -- .../test_data/drop_data_asset/pubspec.yaml | 27 -- .../test_data/drop_dylib_recording/.gitignore | 1 - .../test_data/drop_dylib_recording/README.md | 35 -- .../bin/drop_dylib_recording_calls.dart | 9 - .../bin/drop_dylib_recording_instances.dart | 9 - .../drop_dylib_recording/hook/build.dart | 36 -- .../drop_dylib_recording/hook/link.dart | 82 ----- .../lib/drop_dylib_recording.dart | 5 - .../lib/src/drop_dylib_recording.dart | 28 -- .../src/drop_dylib_recording_bindings.dart | 15 - .../drop_dylib_recording/pubspec.yaml | 28 -- .../drop_dylib_recording/src/native_add.c | 9 - .../drop_dylib_recording/src/native_add.h | 13 - .../src/native_multiply.c | 9 - .../src/native_multiply.h | 13 - pkg/record_use/test_data/manifest.yaml | 24 -- .../lib/src/test_configurations.dart | 1 + pubspec.yaml | 3 +- third_party/.gitignore | 1 + third_party/pkg/record_use.status | 8 + tools/bots/test_matrix.json | 3 +- 58 files changed, 18 insertions(+), 2355 deletions(-) delete mode 100644 pkg/record_use/CHANGELOG.md delete mode 100644 pkg/record_use/LICENSE delete mode 100644 pkg/record_use/OWNERS delete mode 100644 pkg/record_use/README.md delete mode 100644 pkg/record_use/analysis_options.yaml delete mode 100644 pkg/record_use/example/record_use_example.dart delete mode 100644 pkg/record_use/lib/record_use.dart delete mode 100644 pkg/record_use/lib/record_use_internal.dart delete mode 100644 pkg/record_use/lib/src/constant.dart delete mode 100644 pkg/record_use/lib/src/definition.dart delete mode 100644 pkg/record_use/lib/src/helper.dart delete mode 100644 pkg/record_use/lib/src/identifier.dart delete mode 100644 pkg/record_use/lib/src/location.dart delete mode 100644 pkg/record_use/lib/src/metadata.dart delete mode 100644 pkg/record_use/lib/src/record_use.dart delete mode 100644 pkg/record_use/lib/src/recorded_usage_from_file.dart delete mode 100644 pkg/record_use/lib/src/recordings.dart delete mode 100644 pkg/record_use/lib/src/reference.dart delete mode 100644 pkg/record_use/lib/src/version.dart delete mode 100644 pkg/record_use/pubspec.yaml delete mode 100644 pkg/record_use/test/storage_test.dart delete mode 100644 pkg/record_use/test/test_data.dart delete mode 100644 pkg/record_use/test/usage_test.dart delete mode 100644 pkg/record_use/test_data/drop_data_asset/.gitignore delete mode 100644 pkg/record_use/test_data/drop_data_asset/README.md delete mode 100644 pkg/record_use/test_data/drop_data_asset/assets/add.txt delete mode 100644 pkg/record_use/test_data/drop_data_asset/assets/double.txt delete mode 100644 pkg/record_use/test_data/drop_data_asset/assets/multiply.txt delete mode 100644 pkg/record_use/test_data/drop_data_asset/assets/square.txt delete mode 100644 pkg/record_use/test_data/drop_data_asset/bin/drop_data_asset_calls.dart delete mode 100644 pkg/record_use/test_data/drop_data_asset/bin/drop_data_asset_instances.dart delete mode 100644 pkg/record_use/test_data/drop_data_asset/hook/build.dart delete mode 100644 pkg/record_use/test_data/drop_data_asset/hook/link.dart delete mode 100644 pkg/record_use/test_data/drop_data_asset/lib/drop_data_asset.dart delete mode 100644 pkg/record_use/test_data/drop_data_asset/lib/src/drop_data_asset.dart delete mode 100644 pkg/record_use/test_data/drop_data_asset/pubspec.yaml delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/.gitignore delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/README.md delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/bin/drop_dylib_recording_calls.dart delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/bin/drop_dylib_recording_instances.dart delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/hook/build.dart delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/hook/link.dart delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/lib/drop_dylib_recording.dart delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/lib/src/drop_dylib_recording.dart delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/lib/src/drop_dylib_recording_bindings.dart delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/pubspec.yaml delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/src/native_add.c delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/src/native_add.h delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/src/native_multiply.c delete mode 100644 pkg/record_use/test_data/drop_dylib_recording/src/native_multiply.h delete mode 100644 pkg/record_use/test_data/manifest.yaml create mode 100644 third_party/pkg/record_use.status diff --git a/DEPS b/DEPS index 9b66358a59c..3273e5e56b8 100644 --- a/DEPS +++ b/DEPS @@ -140,7 +140,7 @@ vars = { "i18n_rev": "dd8a792a8492370a594706c8304d2eb8db844d7a", "leak_tracker_rev": "f5620600a5ce1c44f65ddaa02001e200b096e14c", # rolled manually "material_color_utilities_rev": "799b6ba2f3f1c28c67cc7e0b4f18e0c7d7f3c03e", - "native_rev": "3ec573500f743d4a1393f7802143aef50fec0a47", # rolled manually while native assets are experimental + "native_rev": "43a691c2152dd9b699259e29356d10edab17ec14", # rolled manually while record_use is experimental "protobuf_rev": "3ed04a91ff4de8493226e8fd0d89678c2986edf6", "pub_rev": "f7f1891e2de3d795532f45ec214f88ac912ffcd6", # rolled manually "shelf_rev": "b924de80e122d1e17b1132bedb02ddb1445b337c", diff --git a/pkg/dartdev/test/native_assets/helpers.dart b/pkg/dartdev/test/native_assets/helpers.dart index 59b07b0c78a..62569129b35 100644 --- a/pkg/dartdev/test/native_assets/helpers.dart +++ b/pkg/dartdev/test/native_assets/helpers.dart @@ -114,7 +114,8 @@ Future copyTestProjects(Uri copyTargetUri, Logger logger, 'code_assets', 'data_assets', 'hooks', - 'native_toolchain_c' + 'native_toolchain_c', + 'record_use', ]) package: { 'path': sdkRoot @@ -124,9 +125,6 @@ Future copyTestProjects(Uri copyTargetUri, Logger logger, 'meta': { 'path': sdkRoot.resolve('pkg/meta/').toFilePath(), }, - 'record_use': { - 'path': sdkRoot.resolve('pkg/record_use/').toFilePath(), - }, }; final userDefinesWorkspace = {}; for (final pubspecPath in pubspecPaths) { @@ -285,7 +283,7 @@ Future recordUseTest( packageUnderTest, fun, const ['drop_dylib_recording', 'drop_data_asset'], - sdkRootUri.resolve('pkg/record_use/'), + sdkRootUri.resolve('third_party/pkg/native/pkgs/record_use/'), sdkRootUri, false, ); diff --git a/pkg/record_use/CHANGELOG.md b/pkg/record_use/CHANGELOG.md deleted file mode 100644 index e0d7d562c4a..00000000000 --- a/pkg/record_use/CHANGELOG.md +++ /dev/null @@ -1,30 +0,0 @@ -## 0.4.2 - -- Fix empty instance parsing. - -## 0.4.1 - -- Fix bug in signature parsing. - -## 0.4.0 - -- Update SDK constraint to `^3.5.0`. -- Rewrite API to expose less symbols. -- Remove locations for easier caching. - -## 0.3.0 - -- Make `InstanceConstant` a `Constant`. -- Separate import from location uri. - -## 0.2.0 - -- Use maps instead of lists in serialization. - -## 0.1.1 - -- Fix repository link. - -## 0.1.0 - -- Initial version. diff --git a/pkg/record_use/LICENSE b/pkg/record_use/LICENSE deleted file mode 100644 index b03a7886835..00000000000 --- a/pkg/record_use/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright 2024, the Dart project authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - * Neither the name of Google LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pkg/record_use/OWNERS b/pkg/record_use/OWNERS deleted file mode 100644 index cd245e30532..00000000000 --- a/pkg/record_use/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -set noparent -file:/tools/OWNERS_ECOSYSTEM -file:/tools/OWNERS_VM -# Global owners -file:/OWNERS diff --git a/pkg/record_use/README.md b/pkg/record_use/README.md deleted file mode 100644 index ce0778cf067..00000000000 --- a/pkg/record_use/README.md +++ /dev/null @@ -1,117 +0,0 @@ -> [!CAUTION] -> This is an experimental package, and it's API can break at any time. Use at -> your own discretion. - -This package provides the data classes for the usage recording feature in the -Dart SDK. - -Dart objects with the `@RecordUse` annotation are being recorded at compile -time, providing the user with information. The information depends on the object -being recorded. - -- If placed on a static method, the annotation means that arguments passed to -the method will be recorded, as far as they can be inferred at compile time. -- If placed on a class with a constant constructor, the annotation means that -any constant instance of the class will be recorded. This is particularly useful -when using the class as an annotation. - -## Example - -```dart -import 'package:meta/meta.dart' show RecordUse; - -void main() { - print(SomeClass.stringMetadata(42)); - print(SomeClass.doubleMetadata(42)); - print(SomeClass.intMetadata(42)); - print(SomeClass.boolMetadata(42)); -} - -class SomeClass { - @RecordMetadata('leroyjenkins') - @RecordUse() - static stringMetadata(int i) { - return i + 1; - } - - @RecordMetadata(3.14) - @RecordUse() - static doubleMetadata(int i) { - return i + 1; - } - - @RecordMetadata(42) - @RecordUse() - static intMetadata(int i) { - return i + 1; - } - - @RecordMetadata(true) - @RecordUse() - static boolMetadata(int i) { - return i + 1; - } -} - -@RecordUse() -class RecordMetadata { - final Object metadata; - - const RecordMetadata(this.metadata); -} - -``` -This code will generate a data file that contains both the `metadata` values of -the `RecordMetadata` instances, as well as the arguments for the different -methods annotated with `@RecordUse()`. - -This information can then be accessed in a link hook as follows: -```dart -import 'dart:convert'; - -import 'package:hooks/hooks.dart'; -import 'package:record_use/record_use_internal.dart'; - -final methodId = Identifier( - uri: 'myfile.dart', - name: 'myMethod', -); - -final classId = Identifier( - uri: 'myfile.dart', - name: 'myClass', -); - -void main(List arguments){ - link(arguments, (config, output) async { - final usesUri = config.recordedUses; - final usesJson = await File,fromUri(usesUri).readAsString(); - final uses = UsageRecord.fromJson(jsonDecode(usesJson)); - - final args = uses.argumentsTo(methodId)); - //[args] is an iterable of arguments, in this case containing "42" - - final fields = uses.instancesOf(classId); - //[fields] is an iterable of the fields of the class, in this case - //containing - // {"arguments": "leroyjenkins"} - // {"arguments": 3.14} - // {"arguments": 42} - // {"arguments": true} - - ... // Do something with the information, such as tree-shaking native assets - }); -} -``` - -## Limitations -As this is designed to work on both web and native platforms, we have to adapt -to the platform pecularities. One of them is that javascript does not support -named arguments, so the dart2js compiler rewrites functions to only accept named -parameters. -While you can use named parameters to record functions, we advise caution as the -retrieval behavior might change once we work around this dart2js limitation and -implement separate positional and named parameters. - -## Contributing -Contributions are welcome! Please open an issue or submit a pull request. diff --git a/pkg/record_use/analysis_options.yaml b/pkg/record_use/analysis_options.yaml deleted file mode 100644 index 127282661ec..00000000000 --- a/pkg/record_use/analysis_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -include: package:dart_flutter_team_lints/analysis_options.yaml - -analyzer: - exclude: [test_data/**] diff --git a/pkg/record_use/example/record_use_example.dart b/pkg/record_use/example/record_use_example.dart deleted file mode 100644 index 8c7ef36e9e0..00000000000 --- a/pkg/record_use/example/record_use_example.dart +++ /dev/null @@ -1,17 +0,0 @@ -// 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:record_use/record_use.dart'; - -void doStuffInLinkHook( - RecordedUsages usage, - Identifier identifier1, - Identifier identifier2, - Identifier identifier3, -) { - print(usage.metadata); - print(usage.constArgumentsFor(identifier1)); - print(usage.constantsOf(identifier2)); - print(usage.hasNonConstArguments(identifier3)); -} diff --git a/pkg/record_use/lib/record_use.dart b/pkg/record_use/lib/record_use.dart deleted file mode 100644 index 8ef2d7e7c35..00000000000 --- a/pkg/record_use/lib/record_use.dart +++ /dev/null @@ -1,8 +0,0 @@ -// 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. - -export 'src/identifier.dart' show Identifier; -export 'src/metadata.dart' show Metadata, MetadataExt; -export 'src/record_use.dart' show ConstantInstance, RecordedUsages; -export 'src/recorded_usage_from_file.dart' show parseFromFile; diff --git a/pkg/record_use/lib/record_use_internal.dart b/pkg/record_use/lib/record_use_internal.dart deleted file mode 100644 index cbb9a75d441..00000000000 --- a/pkg/record_use/lib/record_use_internal.dart +++ /dev/null @@ -1,25 +0,0 @@ -// 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. - -export 'src/constant.dart' - show - BoolConstant, - Constant, - InstanceConstant, - IntConstant, - ListConstant, - MapConstant, - NullConstant, - PrimitiveConstant, - StringConstant; -export 'src/definition.dart' show Definition; -export 'src/identifier.dart' show Identifier; -export 'src/location.dart' show Location; -export 'src/metadata.dart' show Metadata, MetadataExt; -export 'src/record_use.dart' show RecordedUsages; -export 'src/recordings.dart' - show FlattenConstantsExtension, MapifyIterableExtension, Recordings; -export 'src/reference.dart' - show CallReference, CallTearOff, CallWithArguments, InstanceReference; -export 'src/version.dart' show version; diff --git a/pkg/record_use/lib/src/constant.dart b/pkg/record_use/lib/src/constant.dart deleted file mode 100644 index e86f5595f12..00000000000 --- a/pkg/record_use/lib/src/constant.dart +++ /dev/null @@ -1,262 +0,0 @@ -// 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 'helper.dart'; - -const _typeKey = 'type'; -const _valueKey = 'value'; - -/// A constant value that can be recorded and serialized. -/// -/// This supports basic constants such as [bool]s or [int]s, as well as -/// [ListConstant], [MapConstant] or [InstanceConstant] for more complex -/// structures. -/// -/// This follows the AST constant concept from the Dart SDK. -sealed class Constant { - /// Creates a [Constant] object. - const Constant(); - - /// Converts this [Constant] object to a JSON representation. - /// - /// [constants] needs to be passed, as the [Constant]s are normalized and - /// stored separately in the JSON. - Map toJson(Map constants); - - /// Converts this [Constant] to the value it represents. - Object? toValue() => switch (this) { - NullConstant() => null, - PrimitiveConstant p => p.value, - ListConstant l => l.value.map((c) => c.toValue()).toList(), - MapConstant m => m.value.map( - (key, value) => MapEntry(key, value.toValue()), - ), - InstanceConstant i => i.fields.map( - (key, value) => MapEntry(key, value.toValue()), - ), - }; - - /// Creates a [Constant] object from its JSON representation. - /// - /// [constants] needs to be passed, as the [Constant]s are normalized and - /// stored separately in the JSON. - static Constant fromJson( - Map value, - List constants, - ) => switch (value[_typeKey] as String) { - NullConstant._type => const NullConstant(), - BoolConstant._type => BoolConstant(value[_valueKey] as bool), - IntConstant._type => IntConstant(value[_valueKey] as int), - StringConstant._type => StringConstant(value[_valueKey] as String), - ListConstant._type => ListConstant( - (value[_valueKey] as List) - .map((value) => value as int) - .map((value) => constants[value]) - .toList(), - ), - MapConstant._type => MapConstant( - (value[_valueKey] as Map).map( - (key, value) => MapEntry(key, constants[value as int]), - ), - ), - InstanceConstant._type => InstanceConstant( - fields: (value[_valueKey] as Map? ?? {}).map( - (key, value) => MapEntry(key, constants[value as int]), - ), - ), - String() => - throw UnimplementedError('This type is not a supported constant'), - }; -} - -/// Represents the `null` constant value. -final class NullConstant extends Constant { - /// The type identifier for JSON serialization. - static const _type = 'Null'; - - /// Creates a [NullConstant] object. - const NullConstant() : super(); - - @override - Map toJson(Map constants) => - _toJson(_type, null); - - @override - bool operator ==(Object other) => other is NullConstant; - - @override - int get hashCode => 0; -} - -/// Represents a constant value of a primitive type. -sealed class PrimitiveConstant extends Constant { - /// The underlying value of this constant. - final T value; - - /// Creates a [PrimitiveConstant] object with the given [value]. - const PrimitiveConstant(this.value); - - @override - int get hashCode => value.hashCode; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is PrimitiveConstant && other.value == value; - } - - @override - Map toJson(Map constants) => valueToJson(); - - /// Converts this primitive constant to a JSON representation. - Map valueToJson(); -} - -/// Represents a constant boolean value. -final class BoolConstant extends PrimitiveConstant { - /// The type identifier for JSON serialization. - static const _type = 'bool'; - - /// Creates a [BoolConstant] object with the given boolean [value]. - const BoolConstant(super.value); - - @override - Map valueToJson() => _toJson(_type, value); -} - -/// Represents a constant integer value. -final class IntConstant extends PrimitiveConstant { - /// The type identifier for JSON serialization. - static const _type = 'int'; - - /// Creates an [IntConstant] object with the given integer [value]. - const IntConstant(super.value); - - @override - Map valueToJson() => _toJson(_type, value); -} - -/// Represents a constant string value. -final class StringConstant extends PrimitiveConstant { - /// The type identifier for JSON serialization. - static const _type = 'String'; - - /// Creates a [StringConstant] object with the given string [value]. - const StringConstant(super.value); - - @override - Map valueToJson() => _toJson(_type, value); -} - -/// Represents a constant list of [Constant] values. -final class ListConstant extends Constant { - /// The type identifier for JSON serialization. - static const _type = 'list'; - - /// The underlying list of constant values. - final List value; - - /// Creates a [ListConstant] object with the given list of [value]s. - const ListConstant(this.value); - - @override - int get hashCode => deepHash(value); - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is ListConstant && deepEquals(other.value, value); - } - - @override - Map toJson(Map constants) => - _toJson(_type, value.map((constant) => constants[constant]).toList()); -} - -/// Represents a constant map from string keys to [Constant] values. -final class MapConstant extends Constant { - /// The type identifier for JSON serialization. - static const _type = 'map'; - - /// The underlying map of constant values. - final Map value; - - /// Creates a [MapConstant] object with the given map of [value]s. - const MapConstant(this.value); - - @override - int get hashCode => deepHash(value); - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is MapConstant && deepEquals(other.value, value); - } - - @override - Map toJson(Map constants) => _toJson( - _type, - value.map((key, constant) => MapEntry(key, constants[constant]!)), - ); -} - -/// A constant instance of a class with its fields -/// -/// Only as far as they can also be represented by constants. This is more or -/// less the same as a [MapConstant]. -final class InstanceConstant extends Constant { - /// The type identifier for JSON serialization. - static const _type = 'Instance'; - - /// The fields of this instance, mapped from field name to [Constant] value. - final Map fields; - - /// Creates an [InstanceConstant] object with the given [fields]. - const InstanceConstant({required this.fields}); - - /// Creates an [InstanceConstant] object from JSON. - /// - /// [json] is a map representing the JSON structure. - /// [constants] is a list of [Constant] objects that are referenced by index - /// in the JSON. - factory InstanceConstant.fromJson( - Map json, - List constants, - ) { - return InstanceConstant( - fields: json.map( - (key, constantIndex) => MapEntry(key, constants[constantIndex as int]), - ), - ); - } - - @override - Map toJson(Map constants) => _toJson( - _type, - fields.isNotEmpty - ? fields.map( - (name, constantIndex) => MapEntry(name, constants[constantIndex]!), - ) - : null, - ); - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is InstanceConstant && deepEquals(other.fields, fields); - } - - @override - int get hashCode => deepHash(fields); -} - -/// Helper to create the JSON structure of constants by storing the value with -/// the type. -Map _toJson(String type, Object? value) { - return {_typeKey: type, if (value != null) _valueKey: value}; -} diff --git a/pkg/record_use/lib/src/definition.dart b/pkg/record_use/lib/src/definition.dart deleted file mode 100644 index ffc04ffd066..00000000000 --- a/pkg/record_use/lib/src/definition.dart +++ /dev/null @@ -1,42 +0,0 @@ -// 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 'identifier.dart' show Identifier; - -/// A defintion is an [identifier] with its [loadingUnit]. -class Definition { - final Identifier identifier; - final String? loadingUnit; - - const Definition({required this.identifier, this.loadingUnit}); - - static const _identifierKey = 'identifier'; - static const _loadingUnitKey = 'loading_unit'; - - factory Definition.fromJson(Map json) { - return Definition( - identifier: Identifier.fromJson( - json[_identifierKey] as Map, - ), - loadingUnit: json[_loadingUnitKey] as String?, - ); - } - - Map toJson() => { - _identifierKey: identifier.toJson(), - if (loadingUnit != null) _loadingUnitKey: loadingUnit, - }; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is Definition && - other.identifier == identifier && - other.loadingUnit == loadingUnit; - } - - @override - int get hashCode => Object.hash(identifier, loadingUnit); -} diff --git a/pkg/record_use/lib/src/helper.dart b/pkg/record_use/lib/src/helper.dart deleted file mode 100644 index 4141938def9..00000000000 --- a/pkg/record_use/lib/src/helper.dart +++ /dev/null @@ -1,9 +0,0 @@ -// 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:collection/collection.dart'; - -final deepEquals = const DeepCollectionEquality().equals; - -final deepHash = const DeepCollectionEquality().hash; diff --git a/pkg/record_use/lib/src/identifier.dart b/pkg/record_use/lib/src/identifier.dart deleted file mode 100644 index b50a7304142..00000000000 --- a/pkg/record_use/lib/src/identifier.dart +++ /dev/null @@ -1,68 +0,0 @@ -// 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. - -/// Represents a unique identifier for a code element, such as a class, method, -/// or field, within a Dart program. -/// -/// An [Identifier] is used to pinpoint a specific element based on its -/// location and name. It consists of: -/// -/// - `importUri`: The URI of the library where the element is defined. -/// - `parent`: The name of the parent element (e.g., the class name for a -/// method or field). This is optional, as not all elements have parents (e.g. -/// top-level functions). -/// - `name`: The name of the element itself. -class Identifier { - /// The URI of the library where the element is defined. - /// - /// This is given in the form of its package import uri, so that it is OS- and - /// user independent. - final String importUri; - - /// The name of the parent element (e.g., the class name for a method or - /// field). This is optional, as not all elements have parents (e.g. top-level - /// functions). - final String? scope; - - /// The name of the element itself. - final String name; - - /// Creates an [Identifier] object. - /// - /// [importUri] is the URI of the library where the element is defined. - /// [scope] is the optional name of the parent element. - /// [name] is the name of the element. - const Identifier({required this.importUri, this.scope, required this.name}); - - static const String _uriKey = 'uri'; - static const String _scopeKey = 'scope'; - static const String _nameKey = 'name'; - - /// Creates an [Identifier] object from its JSON representation. - factory Identifier.fromJson(Map json) => Identifier( - importUri: json[_uriKey] as String, - scope: json[_scopeKey] as String?, - name: json[_nameKey] as String, - ); - - /// Converts this [Identifier] object to a JSON representation. - Map toJson() => { - _uriKey: importUri, - if (scope != null) _scopeKey: scope, - _nameKey: name, - }; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is Identifier && - other.importUri == importUri && - other.scope == scope && - other.name == name; - } - - @override - int get hashCode => Object.hash(importUri, scope, name); -} diff --git a/pkg/record_use/lib/src/location.dart b/pkg/record_use/lib/src/location.dart deleted file mode 100644 index 73ce2060597..00000000000 --- a/pkg/record_use/lib/src/location.dart +++ /dev/null @@ -1,44 +0,0 @@ -// 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. - -class Location { - final String uri; - final int? line; - final int? column; - - const Location({required this.uri, this.line, this.column}); - - static const _uriKey = 'uri'; - static const _lineKey = 'line'; - static const _columnKey = 'column'; - - factory Location.fromJson(Map map) { - return Location( - uri: map[_uriKey] as String, - line: map[_lineKey] as int?, - column: map[_columnKey] as int?, - ); - } - - Map toJson() { - return { - _uriKey: uri, - if (line != null) _lineKey: line, - if (line != null) _columnKey: column, - }; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is Location && - other.uri == uri && - other.line == line && - other.column == column; - } - - @override - int get hashCode => Object.hash(uri, line, column); -} diff --git a/pkg/record_use/lib/src/metadata.dart b/pkg/record_use/lib/src/metadata.dart deleted file mode 100644 index 819b614f225..00000000000 --- a/pkg/record_use/lib/src/metadata.dart +++ /dev/null @@ -1,41 +0,0 @@ -// 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:pub_semver/pub_semver.dart'; - -import 'helper.dart'; - -/// Metadata attached to a recorded usages file. -/// -/// Whatever [Metadata] should be added to the usage recording. Care should be -/// applied to not include non-deterministic or dynamic data such as timestamps, -/// as this would mess with the usage recording caching. -class Metadata { - /// The underlying data. - /// - /// Together with the metadata extension [MetadataExt], this makes the - /// metadata extensible by the user implementing the recording. For example, - /// dart2js might want to store different metadata than the Dart VM. - final Map json; - - const Metadata._({required this.json}); - - factory Metadata.fromJson(Map json) => - Metadata._(json: json); - - @override - bool operator ==(covariant Metadata other) { - if (identical(this, other)) return true; - - return deepEquals(other.json, json); - } - - @override - int get hashCode => deepHash(json); -} - -extension MetadataExt on Metadata { - Version get version => Version.parse(json['version'] as String); - String get comment => json['comment'] as String; -} diff --git a/pkg/record_use/lib/src/record_use.dart b/pkg/record_use/lib/src/record_use.dart deleted file mode 100644 index 22e956ae9c8..00000000000 --- a/pkg/record_use/lib/src/record_use.dart +++ /dev/null @@ -1,140 +0,0 @@ -// 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 '../record_use_internal.dart'; - -/// Holds all information recorded during compilation. -/// -/// This can be queried using the methods provided, which each take an -/// [Identifier] which must be annotated with `@RecordUse` from `package:meta`. -extension type RecordedUsages._(Recordings _recordings) { - RecordedUsages.fromJson(Map json) - : this._(Recordings.fromJson(json)); - - /// Show the metadata for this recording of usages. - Metadata get metadata => _recordings.metadata; - - /// Finds all const arguments for calls to the [identifier]. - /// - /// The definition must be annotated with `@RecordUse()`. If there are no - /// calls to the definition, either because it was treeshaken, because it was - /// not annotated, or because it does not exist, returns empty. - /// - /// Returns an empty iterable if the arguments were not collected. - /// - /// Example: - /// ```dart - /// import 'package:meta/meta.dart' show ResourceIdentifier; - /// void main() { - /// print(SomeClass.someStaticMethod(42)); - /// } - /// - /// class SomeClass { - /// @ResourceIdentifier('id') - /// static someStaticMethod(int i) { - /// return i + 1; - /// } - /// } - /// ``` - /// - /// Would mean that - /// ``` - /// argumentsTo(Identifier( - /// uri: 'path/to/file.dart', - /// parent: 'SomeClass', - /// name: 'someStaticMethod'), - /// ).first == - /// [ - /// {1: 42} - /// ] - /// ``` - Iterable<({Map named, List positional})> - constArgumentsFor(Identifier identifier) { - return _recordings.calls[identifier]?.whereType().map( - (call) => ( - named: call.namedArguments.map( - (name, argument) => MapEntry(name, argument?.toValue()), - ), - positional: - call.positionalArguments - .map((argument) => argument?.toValue()) - .toList(), - ), - ) ?? - []; - } - - /// Finds all constant fields of a const instance of the class [identifier]. - /// - /// The definition must be annotated with `@RecordUse()`. If there are - /// no instances of the definition, either because it was treeshaken, because - /// it was not annotated, or because it does not exist, returns empty. - /// - /// The types of fields supported are defined at - /// - /// Example: - /// ```dart - /// void main() { - /// print(SomeClass.someStaticMethod(42)); - /// } - /// - /// class SomeClass { - /// @AnnotationClass('freddie') - /// static someStaticMethod(int i) { - /// return i + 1; - /// } - /// } - /// - /// @RecordUse() - /// class AnnotationClass { - /// final String s; - /// const AnnotationClass(this.s); - /// } - /// ``` - /// - /// Would mean that - /// ``` - /// constantsOf(Identifier( - /// uri: 'path/to/file.dart', - /// name: 'AnnotationClass'), - /// ).first['s'] == 'freddie'; - /// ``` - /// - /// What kinds of fields can be recorded depends on the implementation of - /// https://dart-review.googlesource.com/c/sdk/+/369620/13/pkg/vm/lib/transformations/record_use/record_instance.dart - Iterable constantsOf(Identifier identifier) { - return _recordings.instances[identifier]?.map( - (reference) => ConstantInstance(reference.instanceConstant.fields), - ) ?? - []; - } - - /// Checks if any call to [identifier] has non-const arguments, or if any - /// tear-off was recorded. - /// - /// The definition must be annotated with `@RecordUse()`. If there are no - /// calls to the definition, either because it was treeshaken, because it was - /// not annotated, or because it does not exist, returns `false`. - bool hasNonConstArguments(Identifier identifier) { - return (_recordings.calls[identifier] ?? []).any( - (element) => switch (element) { - CallTearOff() => true, - CallWithArguments call => call.positionalArguments.any( - (argument) => argument == null, - ), - }, - ); - } -} - -extension type ConstantInstance(Map _fields) { - bool hasField(String key) => _fields.containsKey(key); - - Object? operator [](String key) { - if (!hasField(key)) { - throw ArgumentError('No field with name $key found.'); - } - return _fields[key]!.toValue(); - } -} diff --git a/pkg/record_use/lib/src/recorded_usage_from_file.dart b/pkg/record_use/lib/src/recorded_usage_from_file.dart deleted file mode 100644 index 4bbe9c41392..00000000000 --- a/pkg/record_use/lib/src/recorded_usage_from_file.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'dart:convert' show jsonDecode; -import 'dart:io' show File; - -import '../record_use_internal.dart' show RecordedUsages; - -RecordedUsages? parseFromFile(Uri? recordedUsagesFile) { - if (recordedUsagesFile == null) { - return null; - } - final usagesContent = File.fromUri(recordedUsagesFile).readAsStringSync(); - final usagesJson = jsonDecode(usagesContent) as Map; - return RecordedUsages.fromJson(usagesJson); -} diff --git a/pkg/record_use/lib/src/recordings.dart b/pkg/record_use/lib/src/recordings.dart deleted file mode 100644 index 4a9badaeb77..00000000000 --- a/pkg/record_use/lib/src/recordings.dart +++ /dev/null @@ -1,259 +0,0 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first -// 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 'dart:convert'; - -import 'constant.dart'; -import 'definition.dart'; -import 'helper.dart'; -import 'identifier.dart'; -import 'location.dart' show Location; -import 'metadata.dart'; -import 'reference.dart'; - -/// [Recordings] combines recordings of calls and instances with metadata. -/// -/// This class acts as the top-level container for recorded usage information. -/// The metadata provides context for the recording, such as version and -/// commentary. The [callsForDefinition] and [instancesForDefinition] store the -/// core data, associating each [Definition] with its corresponding [Reference] -/// details. -/// -/// The class uses a normalized JSON format, allowing the reuse of locations and -/// constants across multiple recordings to optimize storage. -class Recordings { - /// [Metadata] such as the recording protocol version. - final Metadata metadata; - - /// The collected [CallReference]s for each [Definition]. - final Map> callsForDefinition; - - late final Map> calls = callsForDefinition - .map((definition, calls) => MapEntry(definition.identifier, calls)); - - /// The collected [InstanceReference]s for each [Definition]. - final Map> instancesForDefinition; - - late final Map> instances = - instancesForDefinition.map( - (definition, instances) => MapEntry(definition.identifier, instances), - ); - - static const _metadataKey = 'metadata'; - static const _constantsKey = 'constants'; - static const _locationsKey = 'locations'; - static const _recordingsKey = 'recordings'; - static const _callsKey = 'calls'; - static const _instancesKey = 'instances'; - static const _definitionKey = 'definition'; - - Recordings({ - required this.metadata, - required this.callsForDefinition, - required this.instancesForDefinition, - }); - - /// Decodes a JSON representation into a [Recordings] object. - /// - /// The format is specifically designed to reduce redundancy and improve - /// efficiency. Identifiers and constants are stored in separate tables, - /// allowing them to be referenced by index in the `recordings` map. - factory Recordings.fromJson(Map json) { - if (json case { - _constantsKey: List? constantJsons, - _locationsKey: List? locationJsons, - _recordingsKey: List? recordingJsons, - }) { - final constants = []; - for (final constantJsonObj in constantJsons ?? []) { - final constantJson = constantJsonObj as Map; - final constant = Constant.fromJson(constantJson, constants); - if (!constants.contains(constant)) { - constants.add(constant); - } - } - final locations = []; - for (final locationJsonObj in locationJsons ?? []) { - final locationJson = locationJsonObj as Map; - final location = Location.fromJson(locationJson); - if (!locations.contains(location)) { - locations.add(location); - } - } - - final recordings = - recordingJsons?.whereType>() ?? []; - - final recordedCalls = recordings.where( - (recording) => recording[_callsKey] != null, - ); - final recordedInstances = recordings.where( - (recording) => recording[_instancesKey] != null, - ); - - return Recordings( - metadata: Metadata.fromJson(json[_metadataKey] as Map), - callsForDefinition: { - for (final recording in recordedCalls) - Definition.fromJson( - recording[_definitionKey] as Map, - ): - (recording[_callsKey] as List) - .map( - (json) => CallReference.fromJson( - json as Map, - constants, - locations, - ), - ) - .toList(), - }, - instancesForDefinition: { - for (final recording in recordedInstances) - Definition.fromJson( - recording[_definitionKey] as Map, - ): - (recording[_instancesKey] as List) - .map( - (json) => InstanceReference.fromJson( - json as Map, - constants, - locations, - ), - ) - .toList(), - }, - ); - } else { - throw ArgumentError(''' -Invalid JSON format for Recordings: -${const JsonEncoder.withIndent(' ').convert(json)} -'''); - } - } - - /// Encodes this object into a JSON representation. - /// - /// This method normalizes identifiers and constants for storage efficiency. - Map toJson() { - final constants = - { - ...callsForDefinition.values - .expand((calls) => calls) - .whereType() - .expand( - (call) => [ - ...call.positionalArguments, - ...call.namedArguments.values, - ], - ) - .nonNulls, - ...instancesForDefinition.values - .expand((instances) => instances) - .expand( - (instance) => { - ...instance.instanceConstant.fields.values, - instance.instanceConstant, - }, - ), - }.flatten().asMapToIndices; - final locations = - { - ...callsForDefinition.values - .expand((calls) => calls) - .map((call) => call.location) - .nonNulls, - ...instancesForDefinition.values - .expand((instances) => instances) - .map((instance) => instance.location) - .nonNulls, - }.asMapToIndices; - return { - _metadataKey: metadata.json, - if (constants.isNotEmpty) - _constantsKey: - constants.keys - .map((constant) => constant.toJson(constants)) - .toList(), - if (locations.isNotEmpty) - _locationsKey: - locations.keys.map((location) => location.toJson()).toList(), - if (callsForDefinition.isNotEmpty || instancesForDefinition.isNotEmpty) - _recordingsKey: [ - if (callsForDefinition.isNotEmpty) - ...callsForDefinition.entries.map( - (entry) => { - _definitionKey: entry.key.toJson(), - _callsKey: - entry.value - .map((call) => call.toJson(constants, locations)) - .toList(), - }, - ), - if (instancesForDefinition.isNotEmpty) - ...instancesForDefinition.entries.map( - (entry) => { - _definitionKey: entry.key.toJson(), - _instancesKey: - entry.value - .map( - (instance) => instance.toJson(constants, locations), - ) - .toList(), - }, - ), - ], - }; - } - - @override - bool operator ==(covariant Recordings other) { - if (identical(this, other)) return true; - - return other.metadata == metadata && - deepEquals(other.callsForDefinition, callsForDefinition) && - deepEquals(other.instancesForDefinition, instancesForDefinition); - } - - @override - int get hashCode => Object.hash( - metadata.hashCode, - deepHash(callsForDefinition), - deepHash(instancesForDefinition), - ); -} - -extension FlattenConstantsExtension on Iterable { - Set flatten() { - final constants = {}; - for (final constant in this) { - depthFirstSearch(constant, constants); - } - return constants; - } - - void depthFirstSearch(Constant constant, Set collected) { - final children = switch (constant) { - ListConstant() => constant.value, - MapConstant() => constant.value.values, - InstanceConstant() => constant.fields.values, - _ => [], - }; - for (final child in children) { - if (!collected.contains(child)) { - depthFirstSearch(child, collected); - } - } - collected.add(constant); - } -} - -extension MapifyIterableExtension on Iterable { - /// Transform list to map, faster than using list.indexOf - Map get asMapToIndices { - var i = 0; - return {for (final element in this) element: i++}; - } -} diff --git a/pkg/record_use/lib/src/reference.dart b/pkg/record_use/lib/src/reference.dart deleted file mode 100644 index 45443e36f1c..00000000000 --- a/pkg/record_use/lib/src/reference.dart +++ /dev/null @@ -1,198 +0,0 @@ -// 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 'constant.dart'; -import 'helper.dart'; -import 'identifier.dart'; -import 'location.dart' show Location; - -const _loadingUnitKey = 'loading_unit'; - -/// A reference to *something*. -/// -/// The something might be a call or an instance, matching a [CallReference] or -/// an [InstanceReference]. -/// All references have in common that they occur in a [loadingUnit], which we -/// record to be able to piece together which loading units are "related", for -/// example all needing the same asset. -sealed class Reference { - final String? loadingUnit; - final Location? location; - - const Reference({required this.loadingUnit, required this.location}); - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is Reference && - other.loadingUnit == loadingUnit && - other.location == location; - } - - @override - int get hashCode => Object.hash(loadingUnit, location); - - Map toJson( - Map constants, - Map locations, - ) => {_loadingUnitKey: loadingUnit, _locationKey: locations[location]}; -} - -const _locationKey = '@'; -const _positionalKey = 'positional'; -const _namedKey = 'named'; -const _typeKey = 'type'; - -/// A reference to a call to some [Identifier]. -/// -/// This might be an actual call, in which case we record the arguments, or a -/// tear-off, in which case we can't record the arguments. -sealed class CallReference extends Reference { - const CallReference({required super.loadingUnit, required super.location}); - - static CallReference fromJson( - Map json, - List constants, - List locations, - ) { - final loadingUnit = json[_loadingUnitKey] as String?; - final locationIndex = json[_locationKey] as int?; - final location = locationIndex == null ? null : locations[locationIndex]; - return json[_typeKey] == 'tearoff' - ? CallTearOff(loadingUnit: loadingUnit, location: location) - : CallWithArguments( - positionalArguments: - (json[_positionalKey] as List? ?? []) - .whereType() - .map( - (constantsIndex) => - constantsIndex != null - ? constants[constantsIndex] - : null, - ) - .toList(), - namedArguments: (json[_namedKey] as Map? ?? {}) - .map((key, value) => MapEntry(key, value as int?)) - .map( - (name, constantsIndex) => MapEntry( - name, - constantsIndex != null ? constants[constantsIndex] : null, - ), - ), - loadingUnit: loadingUnit, - location: location, - ); - } -} - -/// A reference to a call to some [Identifier] with [positionalArguments] and -/// [namedArguments]. -final class CallWithArguments extends CallReference { - final List positionalArguments; - final Map namedArguments; - - const CallWithArguments({ - required this.positionalArguments, - required this.namedArguments, - required super.loadingUnit, - required super.location, - }); - - @override - Map toJson( - Map constants, - Map locations, - ) { - final positionalJson = - positionalArguments.map((constant) => constants[constant]).toList(); - final namedJson = namedArguments.map( - (name, constant) => MapEntry(name, constants[constant]), - ); - return { - _typeKey: 'with_arguments', - if (positionalJson.isNotEmpty) _positionalKey: positionalJson, - if (namedJson.isNotEmpty) _namedKey: namedJson, - ...super.toJson(constants, locations), - }; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (!(super == other)) return false; - - return other is CallWithArguments && - deepEquals(other.positionalArguments, positionalArguments) && - deepEquals(other.namedArguments, namedArguments); - } - - @override - int get hashCode => Object.hash( - deepHash(positionalArguments), - deepHash(namedArguments), - super.hashCode, - ); -} - -/// A reference to a tear-off use of the [Identifier]. This means that we can't -/// record the arguments possibly passed to the method somewhere else. -final class CallTearOff extends CallReference { - const CallTearOff({required super.loadingUnit, required super.location}); - - @override - Map toJson( - Map constants, - Map locations, - ) { - return {_typeKey: 'tearoff', ...super.toJson(constants, locations)}; - } -} - -final class InstanceReference extends Reference { - final InstanceConstant instanceConstant; - - const InstanceReference({ - required this.instanceConstant, - required super.loadingUnit, - required super.location, - }); - - static const _constantKey = 'constant_index'; - - factory InstanceReference.fromJson( - Map json, - List constants, - List locations, - ) { - final locationIndex = json[_locationKey] as int?; - return InstanceReference( - instanceConstant: - constants[json[_constantKey] as int] as InstanceConstant, - loadingUnit: json[_loadingUnitKey] as String?, - location: locationIndex == null ? null : locations[locationIndex], - ); - } - - @override - Map toJson( - Map constants, - Map locations, - ) => { - _constantKey: constants[instanceConstant]!, - ...super.toJson(constants, locations), - }; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (!(super == other)) return false; - - return other is InstanceReference && - other.instanceConstant == instanceConstant; - } - - @override - int get hashCode => Object.hash(instanceConstant, super.hashCode); -} diff --git a/pkg/record_use/lib/src/version.dart b/pkg/record_use/lib/src/version.dart deleted file mode 100644 index 0e27dc4556c..00000000000 --- a/pkg/record_use/lib/src/version.dart +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2025, 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:pub_semver/pub_semver.dart' show Version; - -final version = Version(0, 4, 0); diff --git a/pkg/record_use/pubspec.yaml b/pkg/record_use/pubspec.yaml deleted file mode 100644 index d7c093fc8f4..00000000000 --- a/pkg/record_use/pubspec.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: record_use -description: > - The serialization logic and API for the usage recording SDK feature. -version: 0.4.2 -repository: https://github.com/dart-lang/sdk/tree/main/pkg/record_use - -environment: - sdk: ^3.7.0 - -resolution: workspace - -dependencies: - collection: ^1.18.0 - pub_semver: ^2.1.4 - -dev_dependencies: - dart_flutter_team_lints: any - lints: any - test: any diff --git a/pkg/record_use/test/storage_test.dart b/pkg/record_use/test/storage_test.dart deleted file mode 100644 index d62610da4a2..00000000000 --- a/pkg/record_use/test/storage_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -// 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 'dart:convert'; - -import 'package:record_use/record_use_internal.dart'; -import 'package:test/test.dart'; - -import 'test_data.dart'; - -void main() { - group('object 1', () { - final json = jsonDecode(recordedUsesJson) as Map; - test('JSON', () => expect(recordedUses.toJson(), json)); - - test('Object', () => expect(Recordings.fromJson(json), recordedUses)); - - test('Json->Object->Json', () { - expect(Recordings.fromJson(json).toJson(), json); - }); - - test('Object->Json->Object', () { - expect(Recordings.fromJson(recordedUses.toJson()), recordedUses); - }); - }); - - group('object 2', () { - final json2 = jsonDecode(recordedUsesJson2) as Map; - test('JSON', () => expect(recordedUses2.toJson(), json2)); - - test('Object', () => expect(Recordings.fromJson(json2), recordedUses2)); - - test('Json->Object->Json', () { - expect(Recordings.fromJson(json2).toJson(), json2); - }); - - test('Object->Json->Object', () { - expect(Recordings.fromJson(recordedUses2.toJson()), recordedUses2); - }); - }); -} diff --git a/pkg/record_use/test/test_data.dart b/pkg/record_use/test/test_data.dart deleted file mode 100644 index 95fd8394146..00000000000 --- a/pkg/record_use/test/test_data.dart +++ /dev/null @@ -1,326 +0,0 @@ -// 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:pub_semver/pub_semver.dart'; -import 'package:record_use/record_use_internal.dart'; - -final callId = Identifier( - importUri: - Uri.parse( - 'file://lib/_internal/js_runtime/lib/js_helper.dart', - ).toString(), - scope: 'MyClass', - name: 'get:loadDeferredLibrary', -); -final instanceId = Identifier( - importUri: - Uri.parse( - 'file://lib/_internal/js_runtime/lib/js_helper.dart', - ).toString(), - name: 'MyAnnotation', -); - -final recordedUses = Recordings( - metadata: Metadata.fromJson({ - 'version': Version(1, 6, 2, pre: 'wip', build: '5.-.2.z').toString(), - 'comment': - 'Recorded references at compile time and their argument values, as' - ' far as known, to definitions annotated with @RecordUse', - }), - callsForDefinition: { - Definition(identifier: callId, loadingUnit: 'part_15.js'): [ - const CallWithArguments( - positionalArguments: [ - StringConstant('lib_SHA1'), - BoolConstant(false), - IntConstant(1), - ], - namedArguments: { - 'freddy': StringConstant('mercury'), - 'leroy': StringConstant('jenkins'), - }, - loadingUnit: 'o.js', - location: Location(uri: 'lib/test.dart'), - ), - const CallWithArguments( - positionalArguments: [ - StringConstant('lib_SHA1'), - MapConstant({'key': IntConstant(99)}), - ListConstant([ - StringConstant('camus'), - ListConstant([ - StringConstant('einstein'), - StringConstant('insert'), - BoolConstant(false), - ]), - StringConstant('einstein'), - ]), - ], - namedArguments: { - 'freddy': IntConstant(0), - 'leroy': StringConstant('jenkins'), - }, - loadingUnit: 'o.js', - location: Location(uri: 'lib/test2.dart'), - ), - ], - }, - instancesForDefinition: { - Definition(identifier: instanceId): [ - const InstanceReference( - instanceConstant: InstanceConstant( - fields: {'a': IntConstant(42), 'b': NullConstant()}, - ), - loadingUnit: '3', - location: Location(uri: 'lib/test3.dart'), - ), - const InstanceReference( - instanceConstant: InstanceConstant(fields: {}), - loadingUnit: '3', - location: Location(uri: 'lib/test3.dart'), - ), - ], - }, -); - -final recordedUses2 = Recordings( - metadata: Metadata.fromJson({ - 'version': Version(1, 6, 2, pre: 'wip', build: '5.-.2.z').toString(), - 'comment': - 'Recorded references at compile time and their argument values, as' - ' far as known, to definitions annotated with @RecordUse', - }), - callsForDefinition: { - Definition(identifier: callId, loadingUnit: 'part_15.js'): [ - const CallWithArguments( - positionalArguments: [BoolConstant(false), IntConstant(1)], - namedArguments: { - 'freddy': StringConstant('mercury'), - 'answer': IntConstant(42), - }, - loadingUnit: 'o.js', - location: Location(uri: 'lib/test3.dart'), - ), - ], - }, - instancesForDefinition: {}, -); - -final recordedUsesJson = '''{ - "metadata": { - "version": "1.6.2-wip+5.-.2.z", - "comment": "Recorded references at compile time and their argument values, as far as known, to definitions annotated with @RecordUse" - }, - "constants": [ - { - "type": "String", - "value": "lib_SHA1" - }, - { - "type": "bool", - "value": false - }, - { - "type": "int", - "value": 1 - }, - { - "type": "String", - "value": "mercury" - }, - { - "type": "String", - "value": "jenkins" - }, - { - "type": "int", - "value": 99 - }, - { - "type": "map", - "value": { - "key": 5 - } - }, - { - "type": "String", - "value": "camus" - }, - { - "type": "String", - "value": "einstein" - }, - { - "type": "String", - "value": "insert" - }, - { - "type": "list", - "value": [ - 8, - 9, - 1 - ] - }, - { - "type": "list", - "value": [ - 7, - 10, - 8 - ] - }, - { - "type": "int", - "value": 0 - }, - { - "type": "int", - "value": 42 - }, - { - "type": "Null" - }, - { - "type": "Instance", - "value": { - "a": 13, - "b": 14 - } - }, - { - "type": "Instance" - } - ], - "locations": [ - { - "uri": "lib/test.dart" - }, - { - "uri": "lib/test2.dart" - }, - { - "uri": "lib/test3.dart" - } - ], - "recordings": [ - { - "definition": { - "identifier": { - "uri": "file://lib/_internal/js_runtime/lib/js_helper.dart", - "scope": "MyClass", - "name": "get:loadDeferredLibrary" - }, - "loading_unit": "part_15.js" - }, - "calls": [ - { - "type": "with_arguments", - "positional": [ - 0, - 1, - 2 - ], - "named": { - "freddy": 3, - "leroy": 4 - }, - "loading_unit": "o.js", - "@": 0 - }, - { - "type": "with_arguments", - "positional": [ - 0, - 6, - 11 - ], - "named": { - "freddy": 12, - "leroy": 4 - }, - "loading_unit": "o.js", - "@": 1 - } - ] - }, - { - "definition": { - "identifier": { - "uri": "file://lib/_internal/js_runtime/lib/js_helper.dart", - "name": "MyAnnotation" - } - }, - "instances": [ - { - "constant_index": 15, - "loading_unit": "3", - "@": 2 - }, - { - "constant_index": 16, - "loading_unit": "3", - "@": 2 - } - ] - } - ] -}'''; - -final recordedUsesJson2 = '''{ - "metadata": { - "version": "1.6.2-wip+5.-.2.z", - "comment": "Recorded references at compile time and their argument values, as far as known, to definitions annotated with @RecordUse" - }, - "constants": [ - { - "type": "bool", - "value": false - }, - { - "type": "int", - "value": 1 - }, - { - "type": "String", - "value": "mercury" - }, - { - "type": "int", - "value": 42 - } - ], - "locations": [ - { - "uri": "lib/test3.dart" - } - ], - "recordings": [ - { - "definition": { - "identifier": { - "uri": "file://lib/_internal/js_runtime/lib/js_helper.dart", - "scope": "MyClass", - "name": "get:loadDeferredLibrary" - }, - "loading_unit": "part_15.js" - }, - "calls": [ - { - "type": "with_arguments", - "positional": [ - 0, - 1 - ], - "named": { - "freddy": 2, - "answer": 3 - }, - "loading_unit": "o.js", - "@": 0 - } - ] - } - ] -}'''; diff --git a/pkg/record_use/test/usage_test.dart b/pkg/record_use/test/usage_test.dart deleted file mode 100644 index e3b2c182fbb..00000000000 --- a/pkg/record_use/test/usage_test.dart +++ /dev/null @@ -1,127 +0,0 @@ -// 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 'dart:convert'; - -import 'package:record_use/record_use_internal.dart'; -import 'package:test/test.dart'; - -import 'test_data.dart'; - -void main() { - test('All API calls', () { - expect( - RecordedUsages.fromJson( - jsonDecode(recordedUsesJson) as Map, - ) - .constArgumentsFor( - Identifier( - importUri: - Uri.parse( - 'file://lib/_internal/js_runtime/lib/js_helper.dart', - ).toString(), - scope: 'MyClass', - name: 'get:loadDeferredLibrary', - ), - ) - .length, - 2, - ); - }); - - test('All API instances', () { - final instance = - RecordedUsages.fromJson( - jsonDecode(recordedUsesJson) as Map, - ) - .constantsOf( - Identifier( - importUri: - Uri.parse( - 'file://lib/_internal/js_runtime/lib/js_helper.dart', - ).toString(), - name: 'MyAnnotation', - ), - ) - .first; - final instanceMap = - recordedUses.instancesForDefinition.values - .expand((usage) => usage) - .map( - (instance) => instance.instanceConstant.fields.map( - (key, constant) => MapEntry(key, constant.toValue()), - ), - ) - .first; - for (final entry in instanceMap.entries) { - expect(instance[entry.key], entry.value); - } - }); - - test('Specific API calls', () { - var arguments = - RecordedUsages.fromJson( - jsonDecode(recordedUsesJson) as Map, - ) - .constArgumentsFor( - Identifier( - importUri: - Uri.parse( - 'file://lib/_internal/js_runtime/lib/js_helper.dart', - ).toString(), - scope: 'MyClass', - name: 'get:loadDeferredLibrary', - ), - ) - .toList(); - var (named: named0, positional: positional0) = arguments[0]; - expect(named0, const {'freddy': 'mercury', 'leroy': 'jenkins'}); - expect(positional0, const ['lib_SHA1', false, 1]); - var (named: named1, positional: positional1) = arguments[1]; - expect(named1, const {'freddy': 0, 'leroy': 'jenkins'}); - expect(positional1, const [ - 'lib_SHA1', - {'key': 99}, - [ - 'camus', - ['einstein', 'insert', false], - 'einstein', - ], - ]); - }); - - test('Specific API instances', () { - final instance = - RecordedUsages.fromJson( - jsonDecode(recordedUsesJson) as Map, - ) - .constantsOf( - Identifier( - importUri: - Uri.parse( - 'file://lib/_internal/js_runtime/lib/js_helper.dart', - ).toString(), - name: 'MyAnnotation', - ), - ) - .first; - expect(instance['a'], 42); - expect(instance['b'], null); - }); - - test('HasNonConstInstance', () { - expect( - RecordedUsages.fromJson( - jsonDecode(recordedUsesJson2) as Map, - ).hasNonConstArguments( - const Identifier( - importUri: - 'package:drop_dylib_recording/src/drop_dylib_recording.dart', - name: 'getMathMethod', - ), - ), - false, - ); - }); -} diff --git a/pkg/record_use/test_data/drop_data_asset/.gitignore b/pkg/record_use/test_data/drop_data_asset/.gitignore deleted file mode 100644 index 953c21190ef..00000000000 --- a/pkg/record_use/test_data/drop_data_asset/.gitignore +++ /dev/null @@ -1 +0,0 @@ -bin/drop_data_asset*/ diff --git a/pkg/record_use/test_data/drop_data_asset/README.md b/pkg/record_use/test_data/drop_data_asset/README.md deleted file mode 100644 index 10cd9d6db57..00000000000 --- a/pkg/record_use/test_data/drop_data_asset/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Tree-shaking Data Assets with Record Use - -This sample demonstrates how the `record-use` feature can be utilized to -tree-shake (remove) unused data assets from the build output. - -## Usage - -The `record-use` and `native-assets` experiments need to be enabled. - -### JS - -Run either `dart compile js --write-resources bin/drop_data_asset_calls.dart` or `dart compile js --write-resources bin/drop_data_asset_instances.dart`. - -### Native - -Run either `dart --enable-experiment=native-assets,record-use build bin/drop_data_asset_calls.dart` or `dart --enable-experiment=native-assets,record-use build bin/drop_data_asset_instances.dart`. - diff --git a/pkg/record_use/test_data/drop_data_asset/assets/add.txt b/pkg/record_use/test_data/drop_data_asset/assets/add.txt deleted file mode 100644 index f8c46162146..00000000000 --- a/pkg/record_use/test_data/drop_data_asset/assets/add.txt +++ /dev/null @@ -1 +0,0 @@ -leroy diff --git a/pkg/record_use/test_data/drop_data_asset/assets/double.txt b/pkg/record_use/test_data/drop_data_asset/assets/double.txt deleted file mode 100644 index 69fbced1baa..00000000000 --- a/pkg/record_use/test_data/drop_data_asset/assets/double.txt +++ /dev/null @@ -1 +0,0 @@ -freddy diff --git a/pkg/record_use/test_data/drop_data_asset/assets/multiply.txt b/pkg/record_use/test_data/drop_data_asset/assets/multiply.txt deleted file mode 100644 index 608ccbb80aa..00000000000 --- a/pkg/record_use/test_data/drop_data_asset/assets/multiply.txt +++ /dev/null @@ -1 +0,0 @@ -jenkins diff --git a/pkg/record_use/test_data/drop_data_asset/assets/square.txt b/pkg/record_use/test_data/drop_data_asset/assets/square.txt deleted file mode 100644 index e52376832b1..00000000000 --- a/pkg/record_use/test_data/drop_data_asset/assets/square.txt +++ /dev/null @@ -1 +0,0 @@ -mercury diff --git a/pkg/record_use/test_data/drop_data_asset/bin/drop_data_asset_calls.dart b/pkg/record_use/test_data/drop_data_asset/bin/drop_data_asset_calls.dart deleted file mode 100644 index c6b16bf2acf..00000000000 --- a/pkg/record_use/test_data/drop_data_asset/bin/drop_data_asset_calls.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2025, 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:drop_data_asset/drop_data_asset.dart'; - -void main(List arguments) { - print('Hello world: ${MyMath.add(3, 4)}!'); -} diff --git a/pkg/record_use/test_data/drop_data_asset/bin/drop_data_asset_instances.dart b/pkg/record_use/test_data/drop_data_asset/bin/drop_data_asset_instances.dart deleted file mode 100644 index 8d1e5c930ff..00000000000 --- a/pkg/record_use/test_data/drop_data_asset/bin/drop_data_asset_instances.dart +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2025, 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:drop_data_asset/drop_data_asset.dart'; - -void main(List arguments) { - print('Hello world: ${MyMath.double(3)}!'); -} diff --git a/pkg/record_use/test_data/drop_data_asset/hook/build.dart b/pkg/record_use/test_data/drop_data_asset/hook/build.dart deleted file mode 100644 index 25b926d2c15..00000000000 --- a/pkg/record_use/test_data/drop_data_asset/hook/build.dart +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2025, 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:data_assets/data_assets.dart'; -import 'package:hooks/hooks.dart'; - -void main(List arguments) async { - await build(arguments, (input, output) async { - for (var element in ['add', 'multiply', 'double', 'square']) { - output.assets.data.add( - DataAsset( - file: input.packageRoot.resolve('assets/$element.txt'), - name: element, - package: input.packageName, - ), - routing: - input.config.linkingEnabled - ? ToLinkHook(input.packageName) - : const ToAppBundle(), - ); - } - }); -} diff --git a/pkg/record_use/test_data/drop_data_asset/hook/link.dart b/pkg/record_use/test_data/drop_data_asset/hook/link.dart deleted file mode 100644 index 893212fe5c2..00000000000 --- a/pkg/record_use/test_data/drop_data_asset/hook/link.dart +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:convert'; -import 'dart:io'; - -import 'package:data_assets/data_assets.dart'; -import 'package:hooks/hooks.dart'; -import 'package:record_use/record_use.dart'; - -void main(List arguments) async { - await link(arguments, (input, output) async { - final recordedUsagesFile = input.recordedUsagesFile; - if (recordedUsagesFile == null) { - throw ArgumentError( - 'Enable the --enable-experiments=record-use experiment to use this app.', - ); - } - final usages = await recordedUsages(recordedUsagesFile); - final dataAssets = input.assets.data; - print('Received assets: ${dataAssets.map((a) => a.id).join(', ')}.'); - - final symbols = {}; - - // Tree-shake unused assets using calls - for (final methodName in ['add', 'multiply']) { - final calls = usages.constArgumentsFor( - Identifier( - importUri: - 'package:${input.packageName}/src/${input.packageName}.dart', - scope: 'MyMath', - name: methodName, - ), - 'int add(int a, int b)', - ); - print('Checking calls to $methodName...'); - for (final call in calls) { - print( - 'A call was made to "$methodName" with the arguments (' - '${call.positional[0] as int},${call.positional[1] as int})', - ); - symbols.add(methodName); - } - } - - // Tree-shake unused assets - final instances = usages.constantsOf( - Identifier( - importUri: 'package:${input.packageName}/src/${input.packageName}.dart', - name: 'RecordCallToC', - ), - ); - for (final instance in instances) { - final symbol = instance['symbol'] as String; - print('An instance of "$instance" was found with the field "$symbol"'); - symbols.add(symbol); - } - - final neededCodeAssets = [ - for (final asset in dataAssets) - if (symbols.any(asset.id.endsWith)) asset, - ]; - - print('Keeping only ${neededCodeAssets.map((e) => e.id).join(', ')}.'); - output.assets.data.addAll(neededCodeAssets); - - output.addDependency(recordedUsagesFile); - }); -} - -Future recordedUsages(Uri recordedUsagesFile) async { - final file = File.fromUri(recordedUsagesFile); - final string = await file.readAsString(); - final usages = RecordedUsages.fromJson( - jsonDecode(string) as Map, - ); - return usages; -} diff --git a/pkg/record_use/test_data/drop_data_asset/lib/drop_data_asset.dart b/pkg/record_use/test_data/drop_data_asset/lib/drop_data_asset.dart deleted file mode 100644 index abb790bfbb5..00000000000 --- a/pkg/record_use/test_data/drop_data_asset/lib/drop_data_asset.dart +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2025, 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. - -export 'src/drop_data_asset.dart'; diff --git a/pkg/record_use/test_data/drop_data_asset/lib/src/drop_data_asset.dart b/pkg/record_use/test_data/drop_data_asset/lib/src/drop_data_asset.dart deleted file mode 100644 index 4da2ab6dd52..00000000000 --- a/pkg/record_use/test_data/drop_data_asset/lib/src/drop_data_asset.dart +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2025, 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:meta/meta.dart'; - -class MyMath { - @RecordUse() - static int add(int a, int b) => a + b; - - @RecordUse() - static int multiply(int a, int b) => a * b; - - @RecordCallToC('double') - static int double(int a) => a + a; - - @RecordCallToC('square') - static int square(int a) => a * a; -} - -@RecordUse() -class RecordCallToC { - final String symbol; - - const RecordCallToC(this.symbol); -} diff --git a/pkg/record_use/test_data/drop_data_asset/pubspec.yaml b/pkg/record_use/test_data/drop_data_asset/pubspec.yaml deleted file mode 100644 index 2a73f57196f..00000000000 --- a/pkg/record_use/test_data/drop_data_asset/pubspec.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: drop_data_asset -description: Add four data assets, remove three in linking based on recorded usage. - -publish_to: none - -environment: - sdk: ^3.7.0 - -dependencies: - hooks: any - data_assets: any - logging: any - meta: any - record_use: - path: ../../../record_use/ - -dev_dependencies: - lints: any - test: any - -dependency_overrides: - meta: - path: ../../../meta/ - hooks: - path: ../../../../third_party/pkg/native/pkgs/hooks/ - data_assets: - path: ../../../../third_party/pkg/native/pkgs/data_assets/ diff --git a/pkg/record_use/test_data/drop_dylib_recording/.gitignore b/pkg/record_use/test_data/drop_dylib_recording/.gitignore deleted file mode 100644 index f486ed6608e..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/.gitignore +++ /dev/null @@ -1 +0,0 @@ -bin/drop_dylib_recording*/ diff --git a/pkg/record_use/test_data/drop_dylib_recording/README.md b/pkg/record_use/test_data/drop_dylib_recording/README.md deleted file mode 100644 index 892aca73fde..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/README.md +++ /dev/null @@ -1,35 +0,0 @@ -This sample builds a native library for adding and multiplying. It then uses -the recorded usages feature to tree-shake unused libraries out. - -## Usage: - -### Keep all: -``` -dart --enable-experiment=record-use build bin/drop_dylib_recording_all.dart -``` -The `lib/` folder now contains both libraries -``` -./bin/drop_dylib_recording_all/drop_dylib_recording_all.exe add -``` -Prints `Hello world: 7!` - - -### Treeshake using calls: -``` -dart --enable-experiment=record-use build bin/drop_dylib_recording_calls.dart -``` -The `lib/` folder now contains only the `add` library. -``` -./bin/drop_dylib_recording_calls/drop_dylib_recording_calls.exe -``` -Prints `Hello world: 7!` - -### Treeshake using instances: -``` -dart --enable-experiment=record-use build bin/drop_dylib_recording_instances.dart -``` -The `lib/` folder now contains only the `add` library. -``` -./bin/drop_dylib_recording_calls/drop_dylib_recording_instances.exe -``` -Prints `Hello world: 7!` diff --git a/pkg/record_use/test_data/drop_dylib_recording/bin/drop_dylib_recording_calls.dart b/pkg/record_use/test_data/drop_dylib_recording/bin/drop_dylib_recording_calls.dart deleted file mode 100644 index d6d77319f5f..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/bin/drop_dylib_recording_calls.dart +++ /dev/null @@ -1,9 +0,0 @@ -// 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:drop_dylib_recording/drop_dylib_recording.dart'; - -void main(List arguments) { - print('Hello world: ${MyMath.add(3, 4)}!'); -} diff --git a/pkg/record_use/test_data/drop_dylib_recording/bin/drop_dylib_recording_instances.dart b/pkg/record_use/test_data/drop_dylib_recording/bin/drop_dylib_recording_instances.dart deleted file mode 100644 index f2165871d38..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/bin/drop_dylib_recording_instances.dart +++ /dev/null @@ -1,9 +0,0 @@ -// 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:drop_dylib_recording/drop_dylib_recording.dart'; - -void main(List arguments) { - print('Hello world: ${MyMath.double(3)}!'); -} diff --git a/pkg/record_use/test_data/drop_dylib_recording/hook/build.dart b/pkg/record_use/test_data/drop_dylib_recording/hook/build.dart deleted file mode 100644 index 726b701e9de..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/hook/build.dart +++ /dev/null @@ -1,36 +0,0 @@ -// 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:logging/logging.dart'; -import 'package:hooks/hooks.dart'; -import 'package:code_assets/code_assets.dart'; -import 'package:native_toolchain_c/native_toolchain_c.dart'; - -void main(List arguments) async { - await build(arguments, (input, output) async { - final logger = - Logger('') - ..level = Level.ALL - ..onRecord.listen((record) { - print('${record.level.name}: ${record.time}: ${record.message}'); - }); - final List routing = - input.config.linkingEnabled - ? [ToLinkHook(input.packageName)] - : const [ToAppBundle()]; - await CBuilder.library( - name: 'add', - assetName: 'dylib_add', - sources: ['src/native_add.c'], - linkModePreference: LinkModePreference.dynamic, - ).run(input: input, output: output, logger: logger, routing: routing); - - await CBuilder.library( - name: 'multiply', - assetName: 'dylib_multiply', - sources: ['src/native_multiply.c'], - linkModePreference: LinkModePreference.dynamic, - ).run(input: input, output: output, logger: logger, routing: routing); - }); -} diff --git a/pkg/record_use/test_data/drop_dylib_recording/hook/link.dart b/pkg/record_use/test_data/drop_dylib_recording/hook/link.dart deleted file mode 100644 index f24e8c69015..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/hook/link.dart +++ /dev/null @@ -1,82 +0,0 @@ -// 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 'dart:convert'; -import 'dart:io'; - -import 'package:hooks/hooks.dart'; -import 'package:code_assets/code_assets.dart'; -import 'package:record_use/record_use.dart'; - -void main(List arguments) async { - await link(arguments, (input, output) async { - final recordedUsagesFile = input.recordedUsagesFile; - if (recordedUsagesFile == null) { - throw ArgumentError( - 'Enable the --enable-experiments=record-use experiment to use this app.', - ); - } - final usages = await recordedUsages(recordedUsagesFile); - final codeAssets = input.assets.code; - print('Received assets: ${codeAssets.map((a) => a.id).join(', ')}.'); - - final symbols = {}; - final argumentsFile = await File.fromUri( - input.outputDirectory.resolve('arguments.txt'), - ).create(); - - final dataLines = []; - // Tree-shake unused assets using calls - for (final methodName in ['add', 'multiply']) { - final calls = usages.constArgumentsFor( - Identifier( - importUri: - 'package:drop_dylib_recording/src/drop_dylib_recording.dart', - scope: 'MyMath', - name: methodName, - ), - ); - for (var call in calls) { - dataLines.add( - 'A call was made to "$methodName" with the arguments (' - '${call.positional[0] as int},${call.positional[1] as int})', - ); - symbols.add(methodName); - } - } - - argumentsFile.writeAsStringSync(dataLines.join('\n')); - - // Tree-shake unused assets - final instances = usages.constantsOf( - Identifier( - importUri: 'package:drop_dylib_recording/src/drop_dylib_recording.dart', - name: 'RecordCallToC', - ), - ); - for (final instance in instances) { - final symbol = instance['symbol'] as String; - symbols.add(symbol); - } - - final neededCodeAssets = [ - for (final codeAsset in codeAssets) - if (symbols.any(codeAsset.id.endsWith)) codeAsset, - ]; - - print('Keeping only ${neededCodeAssets.map((e) => e.id).join(', ')}.'); - output.assets.code.addAll(neededCodeAssets); - - output.addDependency(recordedUsagesFile); - }); -} - -Future recordedUsages(Uri recordedUsagesFile) async { - final file = File.fromUri(recordedUsagesFile); - final string = await file.readAsString(); - final usages = RecordedUsages.fromJson( - jsonDecode(string) as Map, - ); - return usages; -} diff --git a/pkg/record_use/test_data/drop_dylib_recording/lib/drop_dylib_recording.dart b/pkg/record_use/test_data/drop_dylib_recording/lib/drop_dylib_recording.dart deleted file mode 100644 index 4041f227cb4..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/lib/drop_dylib_recording.dart +++ /dev/null @@ -1,5 +0,0 @@ -// 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. - -export 'src/drop_dylib_recording.dart'; diff --git a/pkg/record_use/test_data/drop_dylib_recording/lib/src/drop_dylib_recording.dart b/pkg/record_use/test_data/drop_dylib_recording/lib/src/drop_dylib_recording.dart deleted file mode 100644 index d031ddc580d..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/lib/src/drop_dylib_recording.dart +++ /dev/null @@ -1,28 +0,0 @@ -// 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:meta/meta.dart'; - -import 'drop_dylib_recording_bindings.dart' as bindings; - -class MyMath { - @RecordUse() - static int add(int a, int b) => bindings.add(a, b); - - @RecordUse() - static int multiply(int a, int b) => bindings.multiply(a, b); - - @RecordCallToC('add') - static int double(int a) => bindings.add(a, a); - - @RecordCallToC('multiply') - static int square(int a) => bindings.multiply(a, a); -} - -@RecordUse() -class RecordCallToC { - final String symbol; - - const RecordCallToC(this.symbol); -} diff --git a/pkg/record_use/test_data/drop_dylib_recording/lib/src/drop_dylib_recording_bindings.dart b/pkg/record_use/test_data/drop_dylib_recording/lib/src/drop_dylib_recording_bindings.dart deleted file mode 100644 index 14c81ca7c1a..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/lib/src/drop_dylib_recording_bindings.dart +++ /dev/null @@ -1,15 +0,0 @@ -// 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 'dart:ffi' as ffi; - -@ffi.Native( - assetId: 'package:drop_dylib_recording/dylib_add', -) -external int add(int a, int b); - -@ffi.Native( - assetId: 'package:drop_dylib_recording/dylib_multiply', -) -external int multiply(int a, int b); diff --git a/pkg/record_use/test_data/drop_dylib_recording/pubspec.yaml b/pkg/record_use/test_data/drop_dylib_recording/pubspec.yaml deleted file mode 100644 index 8dc3fc30d0a..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/pubspec.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: drop_dylib_recording -description: Generate two dylibs, remove one in linking based on recorded usage. -version: 1.0.0 - -publish_to: none - -environment: - sdk: ^3.0.0 - -dependencies: - logging: ^1.1.1 - meta: any - hooks: - path: ../../../../third_party/pkg/native/pkgs/hooks/ - code_assets: - path: ../../../../third_party/pkg/native/pkgs/code_assets/ - native_toolchain_c: - path: ../../../../third_party/pkg/native/pkgs/native_toolchain_c/ - record_use: - path: ../../../record_use/ - -dev_dependencies: - lints: any - test: any - -dependency_overrides: - meta: - path: ../../../meta/ diff --git a/pkg/record_use/test_data/drop_dylib_recording/src/native_add.c b/pkg/record_use/test_data/drop_dylib_recording/src/native_add.c deleted file mode 100644 index 570e754fe1b..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/src/native_add.c +++ /dev/null @@ -1,9 +0,0 @@ -// 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. - -#include "native_add.h" - -MYLIB_EXPORT int32_t add(int32_t a, int32_t b) { - return a + b; -} diff --git a/pkg/record_use/test_data/drop_dylib_recording/src/native_add.h b/pkg/record_use/test_data/drop_dylib_recording/src/native_add.h deleted file mode 100644 index 275878fe856..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/src/native_add.h +++ /dev/null @@ -1,13 +0,0 @@ -// 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. - -#include - -#if _WIN32 -#define MYLIB_EXPORT __declspec(dllexport) -#else -#define MYLIB_EXPORT -#endif - -MYLIB_EXPORT int32_t add(int32_t a, int32_t b); diff --git a/pkg/record_use/test_data/drop_dylib_recording/src/native_multiply.c b/pkg/record_use/test_data/drop_dylib_recording/src/native_multiply.c deleted file mode 100644 index 37ad92677e9..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/src/native_multiply.c +++ /dev/null @@ -1,9 +0,0 @@ -// 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. - -#include "native_multiply.h" - -MYLIB_EXPORT intptr_t multiply(intptr_t a, intptr_t b) { - return a * b; -} diff --git a/pkg/record_use/test_data/drop_dylib_recording/src/native_multiply.h b/pkg/record_use/test_data/drop_dylib_recording/src/native_multiply.h deleted file mode 100644 index 1c326f4cae5..00000000000 --- a/pkg/record_use/test_data/drop_dylib_recording/src/native_multiply.h +++ /dev/null @@ -1,13 +0,0 @@ -// 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. - -#include - -#if _WIN32 -#define MYLIB_EXPORT __declspec(dllexport) -#else -#define MYLIB_EXPORT -#endif - -MYLIB_EXPORT intptr_t multiply(intptr_t a, intptr_t b); diff --git a/pkg/record_use/test_data/manifest.yaml b/pkg/record_use/test_data/manifest.yaml deleted file mode 100644 index 66b9eba1b3c..00000000000 --- a/pkg/record_use/test_data/manifest.yaml +++ /dev/null @@ -1,24 +0,0 @@ -- drop_dylib_recording/pubspec.yaml -- drop_dylib_recording/lib/src/drop_dylib_recording_bindings.dart -- drop_dylib_recording/lib/src/drop_dylib_recording.dart -- drop_dylib_recording/lib/drop_dylib_recording.dart -- drop_dylib_recording/src/native_add.h -- drop_dylib_recording/src/native_multiply.h -- drop_dylib_recording/src/native_add.c -- drop_dylib_recording/src/native_multiply.c -- drop_dylib_recording/hook/link.dart -- drop_dylib_recording/hook/build.dart -- drop_dylib_recording/bin/drop_dylib_recording_calls.dart -- drop_dylib_recording/bin/drop_dylib_recording_instances.dart -- drop_data_asset/pubspec.yaml -- drop_data_asset/assets/double.txt -- drop_data_asset/assets/square.txt -- drop_data_asset/assets/add.txt -- drop_data_asset/assets/multiply.txt -- drop_data_asset/lib/drop_data_asset.dart -- drop_data_asset/lib/src/drop_data_asset.dart -- drop_data_asset/README.md -- drop_data_asset/hook/link.dart -- drop_data_asset/hook/build.dart -- drop_data_asset/bin/drop_data_asset_instances.dart -- drop_data_asset/bin/drop_data_asset_calls.dart diff --git a/pkg/test_runner/lib/src/test_configurations.dart b/pkg/test_runner/lib/src/test_configurations.dart index 6153692dee7..2eb328947d8 100644 --- a/pkg/test_runner/lib/src/test_configurations.dart +++ b/pkg/test_runner/lib/src/test_configurations.dart @@ -46,6 +46,7 @@ final testSuiteDirectories = [ Path('third_party/pkg/native/pkgs/hooks_runner'), Path('third_party/pkg/native/pkgs/hooks'), Path('third_party/pkg/native/pkgs/native_toolchain_c'), + Path('third_party/pkg/native/pkgs/record_use'), Path('third_party/pkg/package_config'), Path('utils/tests/peg'), ]; diff --git a/pubspec.yaml b/pubspec.yaml index b68b4065060..9d606fb0f8e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -63,7 +63,6 @@ workspace: - pkg/native_compiler - pkg/native_stack_traces - pkg/node_preamble - - pkg/record_use - pkg/reload_test - pkg/scrape - pkg/server_plugin @@ -227,6 +226,8 @@ dependency_overrides: path: third_party/pkg/native/pkgs/pub_formats pub_semver: path: third_party/pkg/tools/pkgs/pub_semver + record_use: + path: third_party/pkg/native/pkgs/record_use regression_tests: path: third_party/pkg/test/integration_tests/regression shelf: diff --git a/third_party/.gitignore b/third_party/.gitignore index 857ad185cb4..8b2f5a64afe 100644 --- a/third_party/.gitignore +++ b/third_party/.gitignore @@ -28,6 +28,7 @@ !/pkg/hooks_runner.status !/pkg/hooks.status !/pkg/native_toolchain_c.status +!/pkg/record_use.status # These packages are authored in third_party. !/pkg/dap diff --git a/third_party/pkg/record_use.status b/third_party/pkg/record_use.status new file mode 100644 index 00000000000..b789223ccc8 --- /dev/null +++ b/third_party/pkg/record_use.status @@ -0,0 +1,8 @@ +# Copyright (c) 2025, 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. + +example/*: SkipByDesign # These test projects don't work without running pub in the project itself. +lib/src/*: SkipByDesign # These are not tests. +test/json_schema/*: SkipByDesign # Dev dependency not in Dart SDK. + diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json index f4cad089279..c6d875b7f5c 100644 --- a/tools/bots/test_matrix.json +++ b/tools/bots/test_matrix.json @@ -183,7 +183,6 @@ "pkg/kernel/", "pkg/meta/", "pkg/native_stack_traces/", - "pkg/hooks_runner/", "pkg/pkg.status", "pkg/smith/", "pkg/status_file/", @@ -3101,6 +3100,7 @@ "hooks_runner", "hooks", "native_toolchain_c", + "record_use", "package_config", "pkg/pkg/dartdev/test/native_assets" ] @@ -3228,6 +3228,7 @@ "hooks_runner", "hooks", "native_toolchain_c", + "record_use", "package_config", "pkg/pkg/dartdev/test/native_assets" ]