Version 3.15.0-74.0.dev Merge ec734ad538de5f6b5e1eb5217aff56fcf2decf50 into dev
diff --git a/build/config/android/config.gni b/build/config/android/config.gni index dfeccda..7be5116 100644 --- a/build/config/android/config.gni +++ b/build/config/android/config.gni
@@ -81,16 +81,6 @@ llvm_android_toolchain_root = "$android_ndk_root/toolchains/llvm/prebuilt/${android_host_os}-${android_host_arch}" android_toolchain_root = "$android_ndk_root/toolchains/llvm/prebuilt/${android_host_os}-${android_host_arch}" - # Toolchain stuff ------------------------------------------------------------ - - if (component_mode == "shared_library") { - # By appending .cr, we prevent name collisions with libraries already - # loaded by the Android zygote. - android_product_extension = ".cr.so" - } else { - android_product_extension = ".so" - } - # ABI ------------------------------------------------------------------------ if (current_cpu == "x86") {
diff --git a/build/toolchain/android/android_toolchain.gni b/build/toolchain/android/android_toolchain.gni index 1a875bd..4759749 100644 --- a/build/toolchain/android/android_toolchain.gni +++ b/build/toolchain/android/android_toolchain.gni
@@ -51,32 +51,11 @@ ld = "${link_prefix}${prefix}/clang++" readelf = prefix + "/llvm-readelf" nm = prefix + "/llvm-nm" - android_strip = prefix + "/llvm-strip" + strip = prefix + "/llvm-strip" toolchain_os = "android" toolchain_cpu = invoker.toolchain_cpu - # We make the assumption that the gcc_toolchain will produce a soname with - # the following definition. - soname = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" - - stripped_soname = "lib.stripped/${soname}" - temp_stripped_soname = "${stripped_soname}.tmp" - - strip_command = - "$android_strip --strip-unneeded -o $temp_stripped_soname $soname" - replace_command = "if ! cmp -s $temp_stripped_soname $stripped_soname; then mv $temp_stripped_soname $stripped_soname; fi" - postsolink = "$strip_command && $replace_command" - solink_outputs = [ stripped_soname ] - default_output_extension = android_product_extension - - # We make the assumption that the gcc_toolchain will produce an exe with - # the following definition. - exe = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" - stripped_exe = "exe.stripped/$exe" - postlink = "$android_strip --strip-unneeded -o $stripped_exe $exe" - link_outputs = [ stripped_exe ] - toolchain_args = { if (defined(invoker.toolchain_args)) { forward_variables_from(invoker.toolchain_args, "*")
diff --git a/pkg/_js_interop_checks/lib/src/js_interop.dart b/pkg/_js_interop_checks/lib/src/js_interop.dart index 582ce54..625ff5b 100644 --- a/pkg/_js_interop_checks/lib/src/js_interop.dart +++ b/pkg/_js_interop_checks/lib/src/js_interop.dart
@@ -254,26 +254,40 @@ '$node.', ); } else if (argLength == 1) { - var value = node.arguments.positional[0]; - if (value is StringLiteral) { - values.addAll(value.value.split(',')); - } else if (value is StaticGet) { - // Sometimes the CFE will translate the following to a StaticGet of a - // const field: - // - // const String fieldName = 'field'; - // @JS(fieldName) - // - // In this case we derive the name from the intializer of the referenced - // field. - var target = value.target; - if (target is Field && target.isConst) { - final value = target.initializer; - if (value is StringLiteral) { - values.addAll(value.value.split(',')); - } - } - } + values = _getConstructorInvocationValues(node.arguments.positional[0]); + } + } + return values; +} + +List<String> _getConstructorInvocationValues(Expression? value) { + List<String> values = []; + if (value is StringLiteral) { + values.addAll(value.value.split(',')); + } else if (value is StringConcatenation) { + values.addAll( + value.expressions + .map((e) => _getConstructorInvocationValues(e).join(',')) + .join() + .split(','), + ); + } else if (value is ConstantExpression) { + final constant = value.constant; + if (constant is StringConstant) { + values.addAll(constant.value.split(',')); + } + } else if (value is StaticGet) { + // Sometimes the CFE will translate the following to a `StaticGet` of a + // const field: + // + // const String fieldName = 'field'; + // @JS(fieldName) + // + // In this case we derive the name from the intializer of the referenced + // field. + var target = value.target; + if (target is Field && target.isConst) { + return _getConstructorInvocationValues(target.initializer); } } return values;
diff --git a/pkg/analysis_server/test/test_all.dart b/pkg/analysis_server/test/test_all.dart index cc7f99e..19f5089 100644 --- a/pkg/analysis_server/test/test_all.dart +++ b/pkg/analysis_server/test/test_all.dart
@@ -28,7 +28,6 @@ import 'utilities/test_all.dart' as utilities; import 'verify_error_fix_status_test.dart' as verify_error_fix_status; import 'verify_no_io_platform_test.dart' as verify_no_io_platform; -import 'verify_no_utf8_encode_test.dart' as verify_no_utf8_encode; import 'verify_sorted_test.dart' as verify_sorted; import 'verify_tests_test.dart' as verify_tests; @@ -57,7 +56,6 @@ utilities.main(); verify_error_fix_status.main(); verify_no_io_platform.main(); - verify_no_utf8_encode.main(); verify_sorted.main(); verify_tests.main(); defineReflectiveSuite(() {
diff --git a/pkg/analysis_server/test/verify_no_utf8_encode_test.dart b/pkg/analysis_server/test/verify_no_utf8_encode_test.dart deleted file mode 100644 index 8f82550..0000000 --- a/pkg/analysis_server/test/verify_no_utf8_encode_test.dart +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright (c) 2023, 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:collection'; - -import 'package:analyzer/file_system/file_system.dart'; -import 'package:analyzer/file_system/physical_file_system.dart'; -import 'package:analyzer/src/util/file_paths.dart' as file_paths; -import 'package:analyzer_testing/package_root.dart'; -import 'package:test/test.dart'; - -// TODO(scheglov): Remove it after SDK 3.1 published. -void main() { - group('_fe_analyzer_shared', () { - buildTests(packagePath: '_fe_analyzer_shared'); - }); - - group('analyzer', () { - buildTests(packagePath: 'analyzer'); - }); -} - -void buildTests({required String packagePath}) { - var provider = PhysicalResourceProvider.INSTANCE; - var pathContext = provider.pathContext; - var pkgRootPath = pathContext.normalize(packageRoot); - - var libFolder = provider - .getFolder(pkgRootPath) - .getFolder(packagePath) - .getFolder('lib'); - - for (var file in libFolder.allFiles) { - if (file_paths.isDart(pathContext, file.path)) { - test(file.path, () { - var content = file.readAsStringSync(); - if (content.contains('utf8.encode(')) { - fail('Should not use `utf8.encode` before SDK 3.1'); - } - }); - } - } -} - -extension on Folder { - Iterable<File> get allFiles sync* { - var queue = Queue<Folder>(); - queue.add(this); - while (queue.isNotEmpty) { - var current = queue.removeFirst(); - var children = current.getChildren(); - for (var child in children) { - if (child is File) { - yield child; - } else if (child is Folder) { - queue.add(child); - } - } - } - } -}
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart index 801f79a..c05b42f 100644 --- a/pkg/analyzer/lib/src/dart/element/element.dart +++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -4219,6 +4219,12 @@ List<FragmentImpl> get children => const []; @override + ExpressionImpl? get constantInitializer2 { + _ensureEnclosingFragmentReadResolution(); + return super.constantInitializer2; + } + + @override FormalParameterElementImpl get element => _element; @generated @@ -4368,6 +4374,12 @@ } @override + MetadataImpl get metadata { + _ensureEnclosingFragmentReadResolution(); + return super.metadata; + } + + @override List<FormalParameterFragmentImpl> get precedingFragments { return [ for ( @@ -4404,6 +4416,18 @@ FormalParameterElementImpl(firstFragment); } + /// Reads the resolution of the enclosing fragment, which sets the default + /// value and metadata of this fragment. + /// + /// This fragment can be reached before its enclosing fragment is read, + /// for example via [nextFragment] when the element combines the default + /// value and metadata of all its fragments. + void _ensureEnclosingFragmentReadResolution() { + if (enclosingFragment case DeferredResolutionReadingMixin enclosing) { + enclosing._ensureReadResolution(); + } + } + static void _linkFragments<T extends FragmentImpl>( List<T> fragments, { required List<FormalParameterFragmentImpl> Function(T) getFragments,
diff --git a/pkg/analyzer/lib/src/summary/api_signature.dart b/pkg/analyzer/lib/src/summary/api_signature.dart index bf74463..acc6654 100644 --- a/pkg/analyzer/lib/src/summary/api_signature.dart +++ b/pkg/analyzer/lib/src/summary/api_signature.dart
@@ -3,12 +3,14 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:convert'; +import 'dart:math'; import 'dart:typed_data'; import 'package:analyzer/dart/analysis/features.dart'; import 'package:analyzer/src/binary/binary_reader.dart'; import 'package:analyzer/src/binary/binary_writer.dart'; import 'package:analyzer/src/dart/analysis/experiments.dart'; +import 'package:analyzer/src/utilities/hash/blake3.dart'; import 'package:collection/collection.dart'; import 'package:convert/convert.dart'; import 'package:crypto/crypto.dart'; @@ -197,7 +199,215 @@ } } -/// Hash value computed by [ApiSignature]. +/// Collects values and produces a BLAKE3-256 digest. +/// +/// Values are encoded in call order. Integers use their low 32 bits, doubles +/// use 64-bit IEEE 754, and both use little-endian byte order. Booleans use +/// one byte, 0 or 1. Strings use UTF-8 with a 32-bit byte-length prefix. +/// Raw bytes are appended without a length prefix. No type tags are added. +/// +/// Reading the digest finalizes the signature; further additions throw +/// [StateError]. Repeated reads return the same digest. Returned byte and +/// word lists have independent, mutable storage. +final class Blake3ApiSignature { + static final ScalarBlake3 _hasher = ScalarBlake3(); + + final Uint8List _buffer; + final ByteData _data; + final ByteData _doubleBytes = ByteData(8); + int _offset = 0; + Uint8List? _digest; + + /// Created on the first flush. + /// Signatures that fit in [_buffer] use [_hasher] for one-shot hashing. + ScalarBlake3Sink? _sink; + + new() : this._(Uint8List(4096)); + + new _(Uint8List buffer) + : _buffer = buffer, + _data = ByteData.sublistView(buffer); + + /// Collects a boolean. + void addBool(bool value) { + _checkNotFinished(); + _flushIfNeeded(); + _buffer[_offset++] = value ? 1 : 0; + } + + /// Collects bytes without a length prefix or padding. + /// Input is consumed synchronously and is neither modified nor retained. + void addBytes(Uint8List bytes) { + _checkNotFinished(); + + // If bytes fit the buffer, add there and done. + var length = bytes.length; + if (_offset + length <= _buffer.length) { + _buffer.setRange(_offset, _offset + length, bytes); + _offset += length; + return; + } + + // Flush full buffers as needed, keeping the last batch buffered. + var start = 0; + while (start < length) { + _flushIfNeeded(); + var count = min(length - start, _buffer.length - _offset); + _buffer.setRange(_offset, _offset + count, bytes, start); + _offset += count; + start += count; + } + } + + /// Collects a little-endian, double-precision floating point value. + void addDouble(double value) { + _checkNotFinished(); + if (_offset + 8 <= _buffer.length) { + _data.setFloat64(_offset, value, Endian.little); + _offset += 8; + } else { + _doubleBytes.setFloat64(0, value, Endian.little); + addBytes(_doubleBytes.buffer.asUint8List()); + } + } + + void addFeatureSet(FeatureSet featureSet) { + var features = ExperimentStatus.knownFeatures; + addInt(features.length); + for (var feature in features.values) { + addBool(featureSet.isEnabled(feature)); + } + } + + /// Collects the low 32 bits of [value] in little-endian order. + void addInt(int value) { + _checkNotFinished(); + if (_offset + 4 <= _buffer.length) { + _data.setUint32(_offset, value, Endian.little); + _offset += 4; + } else { + for (var shift = 0; shift < 32; shift += 8) { + _addByte(value >> shift); + } + } + } + + void addLanguageVersion(Version version) { + addInt(version.major); + addInt(version.minor); + } + + void addList<T>(List<T> elements, void Function(T) addElement) { + addInt(elements.length); + for (var element in elements) { + addElement(element); + } + } + + void addMapEntryList<K, V>( + List<MapEntry<K, V>> entries, + void Function(K, V) addEntry, + ) { + addInt(entries.length); + for (var entry in entries) { + addEntry(entry.key, entry.value); + } + } + + /// Collects the UTF-8 byte length followed by the UTF-8 bytes of [value]. + void addString(String value) { + _checkNotFinished(); + + // Use UTF-8 encoding if any character is non-ASCII. + var length = value.length; + for (var i = 0; i < length; i++) { + if (value.codeUnitAt(i) >= 128) { + var bytes = utf8.encode(value); + addInt(bytes.length); + addBytes(bytes); + return; + } + } + + // Write ASCII bytes directly when the length prefix and string fit. + if (_offset + 4 + length <= _buffer.length) { + _data.setUint32(_offset, length, Endian.little); + _offset += 4; + for (var i = 0; i < length; i++) { + _buffer[_offset + i] = value.codeUnitAt(i); + } + _offset += length; + return; + } + + // Write ASCII bytes across buffer boundaries when they do not fit. + addInt(length); + var start = 0; + while (start < length) { + _flushIfNeeded(); + var count = length - start; + var space = _buffer.length - _offset; + if (count > space) count = space; + for (var i = 0; i < count; i++) { + _buffer[_offset + i] = value.codeUnitAt(start + i); + } + _offset += count; + start += count; + } + } + + void addStringList(List<String> values) { + addList(values, addString); + } + + /// Collects the backing buffer's bytes, matching [ApiSignature.addUint32List]. + void addUint32List(Uint32List data) { + addBytes(data.buffer.asUint8List()); + } + + /// Finalizes the signature and returns its 32-byte digest. + Uint8List toByteList() => Uint8List.fromList(_digest ??= _finish()); + + /// Finalizes the signature and returns its hash value. + Hash toHash() => Hash._(_digest ??= _finish()); + + /// Finalizes the signature and returns its hex-encoded digest. + String toHex() => hex.encode(_digest ??= _finish()); + + /// Finalizes the signature and returns its digest as eight native-endian words. + Uint32List toUint32List() => toByteList().buffer.asUint32List(); + + void _addByte(int value) { + _flushIfNeeded(); + _buffer[_offset++] = value; + } + + void _checkNotFinished() { + if (_digest != null) { + throw StateError('The API signature is already finalized.'); + } + } + + Uint8List _finish() { + var bytes = Uint8List.sublistView(_buffer, 0, _offset); + var sink = _sink; + if (sink == null) return _hasher.hash(bytes); + sink.add(bytes); + return sink.finish(); + } + + void _flush() { + assert(_offset == _buffer.length); + (_sink ??= ScalarBlake3Sink()).add(_buffer); + _offset = 0; + } + + void _flushIfNeeded() { + if (_offset == _buffer.length) _flush(); + } +} + +/// Hash value computed from an API signature. class Hash { static final Hash empty = Hash._(Uint8List(0));
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart index 1efb187..fdc625b 100644 --- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart +++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -55,10 +55,6 @@ AnalysisOptionsImpl analysisOptions, PropertyInducingElementImpl element, ) { - if (element is FieldElementImpl && element.isEnumConstant) { - return; - } - // Every fragment's initializer is written into the bundle, including // initializers of augmentations, so each of them must end up resolved. for (var fragment in element.fragments) {
diff --git a/pkg/analyzer/lib/src/utilities/hash/blake3.dart b/pkg/analyzer/lib/src/utilities/hash/blake3.dart new file mode 100644 index 0000000..892544c --- /dev/null +++ b/pkg/analyzer/lib/src/utilities/hash/blake3.dart
@@ -0,0 +1,26 @@ +// 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. + +import 'dart:typed_data'; + +part 'blake3_internal.dart'; +part 'blake3_scalar_compression.dart'; +part 'blake3_streaming.dart'; + +/// Computes unkeyed BLAKE3-256 digests of byte sequences. +/// +/// An instance reuses its scratch storage between synchronous [hash] calls. +/// For incremental input, use [ScalarBlake3Sink]. +abstract interface class Blake3 { + /// Returns the 32-byte digest of precisely the bytes in [input]. + /// + /// Arbitrarily offset views and unmodifiable inputs are supported. Input is + /// never modified or retained. Every digest has independent, mutable storage. + Uint8List hash(Uint8List input); +} + +/// BLAKE3 using scalar integer arithmetic. +abstract final class ScalarBlake3 implements Blake3 { + factory() = _ScalarBlake3; +}
diff --git a/pkg/analyzer/lib/src/utilities/hash/blake3_internal.dart b/pkg/analyzer/lib/src/utilities/hash/blake3_internal.dart new file mode 100644 index 0000000..79f5973 --- /dev/null +++ b/pkg/analyzer/lib/src/utilities/hash/blake3_internal.dart
@@ -0,0 +1,179 @@ +// 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 'blake3.dart'; + +const _blake3Iv = [ + 0x6a09e667, + 0xbb67ae85, + 0x3c6ef372, + 0xa54ff53a, + 0x510e527f, + 0x9b05688c, + 0x1f83d9ab, + 0x5be0cd19, +]; +const _chunkEnd = 2; +const _chunkStart = 1; +const _parentFlag = 4; +const _rootFlag = 8; + +/// Chunk processing, tree traversal, and reusable scratch storage. +/// +/// See the [BLAKE3 project](https://github.com/BLAKE3-team/BLAKE3) for the +/// specification and reference implementation. +abstract class _Blake3Base { + static const int _blockSizeInBytes = 64; + static const int _blockSizeInWords = 16; + static const int _chunkSizeInBytes = 1024; + + final Uint32List _chainingValue = Uint32List(8); + final Uint32List _parentBlock = Uint32List(_blockSizeInWords); + final Uint32List _tailWords = Uint32List(_blockSizeInWords); + final Uint32List _cvStack = Uint32List(54 * 8); + + /// Returns the 32-byte digest of precisely the bytes in [input]. + /// + /// Arbitrarily offset views and unmodifiable inputs are supported. Output + /// does not alias [input] or the output of any previous call. + Uint8List hash(Uint8List input) { + // Normalize subviews once for aligned word loads. Ordinary Uint8List + // inputs need no copy. + if (input.offsetInBytes % 4 != 0) { + input = Uint8List.fromList(input); + } + var words = Uint32List.view( + input.buffer, + input.offsetInBytes, + input.length ~/ 4, + ); + var stackLength = 0; + var chunkCount = + (input.length + _chunkSizeInBytes - 1) ~/ _chunkSizeInBytes; + var chunks = chunkCount == 0 ? 1 : chunkCount; + for (var chunk = 0; chunk < chunks; chunk++) { + var start = chunk * _chunkSizeInBytes; + var remaining = input.length - start; + var chunkLength = remaining < _chunkSizeInBytes + ? remaining + : _chunkSizeInBytes; + var fullBlocks = chunkLength ~/ _blockSizeInBytes; + var tailLength = chunkLength % _blockSizeInBytes; + var endFlags = _chunkEnd | (chunks == 1 ? _rootFlag : 0); + if (fullBlocks > 0) { + _compressChunkBlocks( + words, + start ~/ 4, + chunk, + fullBlocks, + tailLength == 0 ? endFlags : 0, + ); + } else { + _resetCv(); + } + if (tailLength != 0 || chunkLength == 0) { + _tailWords.fillRange(0, _blockSizeInWords, 0); + Uint8List.view(_tailWords.buffer).setRange( + 0, + tailLength, + input, + start + fullBlocks * _blockSizeInBytes, + ); + _compress( + _chainingValue, + _tailWords, + 0, + chunk, + tailLength, + endFlags | (fullBlocks == 0 ? _chunkStart : 0), + ); + } + if (chunk == chunks - 1) { + _finishCv(stackLength); + } else { + stackLength = _pushCv(chunk + 1, stackLength); + } + } + return Uint8List.fromList(Uint8List.view(_chainingValue.buffer)); + } + + void _compress( + Uint32List cv, + Uint32List words, + int offset, + int counter, + int blockLength, + int flags, + ); + + /// Starts a chunk and consumes its complete blocks. + /// + /// Only the last block may receive CHUNK_END/ROOT; a partial final block is + /// handled by [hash] afterward. + void _compressChunkBlocks( + Uint32List words, + int offset, + int counter, + int blocks, + int lastFlags, + ) { + _resetCv(); + for (var block = 0; block < blocks; block++) { + _compress( + _chainingValue, + words, + offset + block * _blockSizeInWords, + counter, + _blockSizeInBytes, + (block == 0 ? _chunkStart : 0) | (block == blocks - 1 ? lastFlags : 0), + ); + } + } + + /// Combines a stacked left child with the current right child, replacing + /// [_chainingValue]. + void _compressStackParent(int offset, int flags) { + _parentBlock.setRange(0, 8, _cvStack, offset); + _parentBlock.setRange(8, _blockSizeInWords, _chainingValue); + _resetCv(); + _compress(_chainingValue, _parentBlock, 0, 0, _blockSizeInBytes, flags); + } + + void _finishCv(int stackLength) { + while (stackLength > 0) { + stackLength--; + _compressStackParent( + stackLength * 8, + _parentFlag | (stackLength == 0 ? _rootFlag : 0), + ); + } + } + + int _pushCv(int count, int stackLength) { + while (count.isEven) { + stackLength--; + _compressStackParent(stackLength * 8, _parentFlag); + count >>= 1; + } + _cvStack.setRange(stackLength * 8, (stackLength + 1) * 8, _chainingValue); + return stackLength + 1; + } + + /// Resets the chaining value to the initialization vector. + /// + /// Direct stores avoid a generic `List<int>`-to-typed-data copy in this hot + /// operation. + @pragma('vm:prefer-inline') + void _resetCv() { + // Write the highest index first to eliminate subsequent bounds checks. + _chainingValue[7] = _blake3Iv[7]; + _chainingValue[0] = _blake3Iv[0]; + _chainingValue[1] = _blake3Iv[1]; + _chainingValue[2] = _blake3Iv[2]; + _chainingValue[3] = _blake3Iv[3]; + _chainingValue[4] = _blake3Iv[4]; + _chainingValue[5] = _blake3Iv[5]; + _chainingValue[6] = _blake3Iv[6]; + } +}
diff --git a/pkg/analyzer/lib/src/utilities/hash/blake3_scalar_compression.dart b/pkg/analyzer/lib/src/utilities/hash/blake3_scalar_compression.dart new file mode 100644 index 0000000..70aeef5 --- /dev/null +++ b/pkg/analyzer/lib/src/utilities/hash/blake3_scalar_compression.dart
@@ -0,0 +1,852 @@ +// 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. + +// Generated by pkg/analyzer/tool/blake3/generate.dart. Do not edit. + +part of 'blake3.dart'; + +/// Compresses one 64-byte block with four independent scalar chains. +final class _ScalarBlake3 extends _Blake3Base implements ScalarBlake3 { + @override + void _compress( + Uint32List cv, + Uint32List words, + int offset, + int counter, + int blockLength, + int flags, + ) { + var v0 = cv[0]; + var v1 = cv[1]; + var v2 = cv[2]; + var v3 = cv[3]; + var v4 = cv[4]; + var v5 = cv[5]; + var v6 = cv[6]; + var v7 = cv[7]; + var v8 = _blake3Iv[0]; + var v9 = _blake3Iv[1]; + var v10 = _blake3Iv[2]; + var v11 = _blake3Iv[3]; + var v12 = counter & 0xffffffff; + var v13 = counter >>> 32; + var v14 = blockLength; + var v15 = flags; + var m0 = words[offset + 0]; + var m1 = words[offset + 1]; + var m2 = words[offset + 2]; + var m3 = words[offset + 3]; + var m4 = words[offset + 4]; + var m5 = words[offset + 5]; + var m6 = words[offset + 6]; + var m7 = words[offset + 7]; + var m8 = words[offset + 8]; + var m9 = words[offset + 9]; + var m10 = words[offset + 10]; + var m11 = words[offset + 11]; + var m12 = words[offset + 12]; + var m13 = words[offset + 13]; + var m14 = words[offset + 14]; + var m15 = words[offset + 15]; + + // Round 1. + // g(0, 4, 8, 12), permutation #0 + v0 = (v0 + v4 + m0) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v0 = (v0 + v4 + m1) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + + // g(1, 5, 9, 13), permutation #0 + v1 = (v1 + v5 + m2) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v1 = (v1 + v5 + m3) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(2, 6, 10, 14), permutation #0 + v2 = (v2 + v6 + m4) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v2 = (v2 + v6 + m5) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(3, 7, 11, 15), permutation #0 + v3 = (v3 + v7 + m6) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v3 = (v3 + v7 + m7) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(0, 5, 10, 15), permutation #0 + v0 = (v0 + v5 + m8) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v0 = (v0 + v5 + m9) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(1, 6, 11, 12), permutation #0 + v1 = (v1 + v6 + m10) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v1 = (v1 + v6 + m11) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(2, 7, 8, 13), permutation #0 + v2 = (v2 + v7 + m12) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v2 = (v2 + v7 + m13) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(3, 4, 9, 14), permutation #0 + v3 = (v3 + v4 + m14) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v3 = (v3 + v4 + m15) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + + // Round 2. + // g(0, 4, 8, 12), permutation #1 + v0 = (v0 + v4 + m2) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v0 = (v0 + v4 + m6) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + + // g(1, 5, 9, 13), permutation #1 + v1 = (v1 + v5 + m3) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v1 = (v1 + v5 + m10) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(2, 6, 10, 14), permutation #1 + v2 = (v2 + v6 + m7) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v2 = (v2 + v6 + m0) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(3, 7, 11, 15), permutation #1 + v3 = (v3 + v7 + m4) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v3 = (v3 + v7 + m13) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(0, 5, 10, 15), permutation #1 + v0 = (v0 + v5 + m1) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v0 = (v0 + v5 + m11) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(1, 6, 11, 12), permutation #1 + v1 = (v1 + v6 + m12) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v1 = (v1 + v6 + m5) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(2, 7, 8, 13), permutation #1 + v2 = (v2 + v7 + m9) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v2 = (v2 + v7 + m14) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(3, 4, 9, 14), permutation #1 + v3 = (v3 + v4 + m15) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v3 = (v3 + v4 + m8) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + + // Round 3. + // g(0, 4, 8, 12), permutation #2 + v0 = (v0 + v4 + m3) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v0 = (v0 + v4 + m4) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + + // g(1, 5, 9, 13), permutation #2 + v1 = (v1 + v5 + m10) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v1 = (v1 + v5 + m12) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(2, 6, 10, 14), permutation #2 + v2 = (v2 + v6 + m13) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v2 = (v2 + v6 + m2) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(3, 7, 11, 15), permutation #2 + v3 = (v3 + v7 + m7) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v3 = (v3 + v7 + m14) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(0, 5, 10, 15), permutation #2 + v0 = (v0 + v5 + m6) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v0 = (v0 + v5 + m5) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(1, 6, 11, 12), permutation #2 + v1 = (v1 + v6 + m9) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v1 = (v1 + v6 + m0) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(2, 7, 8, 13), permutation #2 + v2 = (v2 + v7 + m11) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v2 = (v2 + v7 + m15) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(3, 4, 9, 14), permutation #2 + v3 = (v3 + v4 + m8) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v3 = (v3 + v4 + m1) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + + // Round 4. + // g(0, 4, 8, 12), permutation #3 + v0 = (v0 + v4 + m10) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v0 = (v0 + v4 + m7) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + + // g(1, 5, 9, 13), permutation #3 + v1 = (v1 + v5 + m12) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v1 = (v1 + v5 + m9) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(2, 6, 10, 14), permutation #3 + v2 = (v2 + v6 + m14) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v2 = (v2 + v6 + m3) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(3, 7, 11, 15), permutation #3 + v3 = (v3 + v7 + m13) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v3 = (v3 + v7 + m15) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(0, 5, 10, 15), permutation #3 + v0 = (v0 + v5 + m4) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v0 = (v0 + v5 + m0) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(1, 6, 11, 12), permutation #3 + v1 = (v1 + v6 + m11) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v1 = (v1 + v6 + m2) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(2, 7, 8, 13), permutation #3 + v2 = (v2 + v7 + m5) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v2 = (v2 + v7 + m8) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(3, 4, 9, 14), permutation #3 + v3 = (v3 + v4 + m1) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v3 = (v3 + v4 + m6) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + + // Round 5. + // g(0, 4, 8, 12), permutation #4 + v0 = (v0 + v4 + m12) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v0 = (v0 + v4 + m13) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + + // g(1, 5, 9, 13), permutation #4 + v1 = (v1 + v5 + m9) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v1 = (v1 + v5 + m11) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(2, 6, 10, 14), permutation #4 + v2 = (v2 + v6 + m15) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v2 = (v2 + v6 + m10) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(3, 7, 11, 15), permutation #4 + v3 = (v3 + v7 + m14) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v3 = (v3 + v7 + m8) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(0, 5, 10, 15), permutation #4 + v0 = (v0 + v5 + m7) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v0 = (v0 + v5 + m2) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(1, 6, 11, 12), permutation #4 + v1 = (v1 + v6 + m5) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v1 = (v1 + v6 + m3) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(2, 7, 8, 13), permutation #4 + v2 = (v2 + v7 + m0) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v2 = (v2 + v7 + m1) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(3, 4, 9, 14), permutation #4 + v3 = (v3 + v4 + m6) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v3 = (v3 + v4 + m4) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + + // Round 6. + // g(0, 4, 8, 12), permutation #5 + v0 = (v0 + v4 + m9) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v0 = (v0 + v4 + m14) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + + // g(1, 5, 9, 13), permutation #5 + v1 = (v1 + v5 + m11) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v1 = (v1 + v5 + m5) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(2, 6, 10, 14), permutation #5 + v2 = (v2 + v6 + m8) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v2 = (v2 + v6 + m12) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(3, 7, 11, 15), permutation #5 + v3 = (v3 + v7 + m15) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v3 = (v3 + v7 + m1) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(0, 5, 10, 15), permutation #5 + v0 = (v0 + v5 + m13) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v0 = (v0 + v5 + m3) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(1, 6, 11, 12), permutation #5 + v1 = (v1 + v6 + m0) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v1 = (v1 + v6 + m10) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(2, 7, 8, 13), permutation #5 + v2 = (v2 + v7 + m2) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v2 = (v2 + v7 + m6) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(3, 4, 9, 14), permutation #5 + v3 = (v3 + v4 + m4) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v3 = (v3 + v4 + m7) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + + // Round 7. + // g(0, 4, 8, 12), permutation #6 + v0 = (v0 + v4 + m11) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v0 = (v0 + v4 + m15) & 0xffffffff; + v12 ^= v0; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v8 = (v8 + v12) & 0xffffffff; + v4 ^= v8; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + + // g(1, 5, 9, 13), permutation #6 + v1 = (v1 + v5 + m5) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v1 = (v1 + v5 + m0) & 0xffffffff; + v13 ^= v1; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v9 = (v9 + v13) & 0xffffffff; + v5 ^= v9; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(2, 6, 10, 14), permutation #6 + v2 = (v2 + v6 + m1) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v2 = (v2 + v6 + m9) & 0xffffffff; + v14 ^= v2; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v10 = (v10 + v14) & 0xffffffff; + v6 ^= v10; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(3, 7, 11, 15), permutation #6 + v3 = (v3 + v7 + m8) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v3 = (v3 + v7 + m6) & 0xffffffff; + v15 ^= v3; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v11 = (v11 + v15) & 0xffffffff; + v7 ^= v11; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(0, 5, 10, 15), permutation #6 + v0 = (v0 + v5 + m14) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 16) | (v15 << 16)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 12) | (v5 << 20)) & 0xffffffff; + v0 = (v0 + v5 + m10) & 0xffffffff; + v15 ^= v0; + v15 = ((v15 >>> 8) | (v15 << 24)) & 0xffffffff; + v10 = (v10 + v15) & 0xffffffff; + v5 ^= v10; + v5 = ((v5 >>> 7) | (v5 << 25)) & 0xffffffff; + + // g(1, 6, 11, 12), permutation #6 + v1 = (v1 + v6 + m2) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 16) | (v12 << 16)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 12) | (v6 << 20)) & 0xffffffff; + v1 = (v1 + v6 + m12) & 0xffffffff; + v12 ^= v1; + v12 = ((v12 >>> 8) | (v12 << 24)) & 0xffffffff; + v11 = (v11 + v12) & 0xffffffff; + v6 ^= v11; + v6 = ((v6 >>> 7) | (v6 << 25)) & 0xffffffff; + + // g(2, 7, 8, 13), permutation #6 + v2 = (v2 + v7 + m3) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 16) | (v13 << 16)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 12) | (v7 << 20)) & 0xffffffff; + v2 = (v2 + v7 + m4) & 0xffffffff; + v13 ^= v2; + v13 = ((v13 >>> 8) | (v13 << 24)) & 0xffffffff; + v8 = (v8 + v13) & 0xffffffff; + v7 ^= v8; + v7 = ((v7 >>> 7) | (v7 << 25)) & 0xffffffff; + + // g(3, 4, 9, 14), permutation #6 + v3 = (v3 + v4 + m7) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 16) | (v14 << 16)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 12) | (v4 << 20)) & 0xffffffff; + v3 = (v3 + v4 + m13) & 0xffffffff; + v14 ^= v3; + v14 = ((v14 >>> 8) | (v14 << 24)) & 0xffffffff; + v9 = (v9 + v14) & 0xffffffff; + v4 ^= v9; + v4 = ((v4 >>> 7) | (v4 << 25)) & 0xffffffff; + cv[0] = v0 ^ v8; + cv[1] = v1 ^ v9; + cv[2] = v2 ^ v10; + cv[3] = v3 ^ v11; + cv[4] = v4 ^ v12; + cv[5] = v5 ^ v13; + cv[6] = v6 ^ v14; + cv[7] = v7 ^ v15; + } +}
diff --git a/pkg/analyzer/lib/src/utilities/hash/blake3_streaming.dart b/pkg/analyzer/lib/src/utilities/hash/blake3_streaming.dart new file mode 100644 index 0000000..4c34756 --- /dev/null +++ b/pkg/analyzer/lib/src/utilities/hash/blake3_streaming.dart
@@ -0,0 +1,122 @@ +// 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 'blake3.dart'; + +/// Incrementally computes an unkeyed BLAKE3-256 digest using scalar arithmetic. +/// +/// Input bytes are consumed synchronously and never retained or modified. +/// [finish] returns independently owned bytes and rejects further input until +/// [reset]. Resetting also permits discarding an unfinished message. +final class ScalarBlake3Sink { + final _ScalarBlake3 _core = _ScalarBlake3(); + late final Uint8List _block = Uint8List.view(_core._tailWords.buffer); + + // Retain the last block, even when full: its CHUNK_END and ROOT flags depend + // on whether more input follows. Empty writes must not compress this block. + int _blockLength = 0; + int _blocksCompressed = 0; + int _chunkCounter = 0; + int _stackLength = 0; + bool _isFinished = false; + + new() { + _core._resetCv(); + } + + /// Adds [input] to the current message. + /// + /// Arbitrarily offset views are supported. Throws [StateError] after [finish], + /// including for empty input. + void add(Uint8List input) { + if (_isFinished) throw StateError('BLAKE3 input is already finalized.'); + var start = 0; + var end = input.length; + while (start < end) { + if (_blockLength == _Blake3Base._blockSizeInBytes) { + _compressBlock(_core._tailWords, 0); + _blockLength = 0; + } + + // Compress aligned complete blocks directly from typed input. Leave at + // least one byte unconsumed so the final block is handled by finish(). + if (_blockLength == 0 && + end - start > _Blake3Base._blockSizeInBytes && + (input.offsetInBytes + start) % 4 == 0) { + var words = Uint32List.view( + input.buffer, + input.offsetInBytes + start, + (end - start) ~/ 4, + ); + var offset = 0; + while (end - start > _Blake3Base._blockSizeInBytes) { + _compressBlock(words, offset); + offset += _Blake3Base._blockSizeInWords; + start += _Blake3Base._blockSizeInBytes; + } + } + + var count = end - start; + var space = _Blake3Base._blockSizeInBytes - _blockLength; + if (count > space) count = space; + _block.setRange(_blockLength, _blockLength + count, input, start); + _blockLength += count; + start += count; + } + } + + /// Finalizes the message and returns its 32-byte digest. + /// + /// Repeated calls return the same digest in independent, mutable storage. + Uint8List finish() { + if (!_isFinished) { + _block.fillRange(_blockLength, _Blake3Base._blockSizeInBytes, 0); + _core._compress( + _core._chainingValue, + _core._tailWords, + 0, + _chunkCounter, + _blockLength, + _chunkEnd | + (_blocksCompressed == 0 ? _chunkStart : 0) | + (_chunkCounter == 0 ? _rootFlag : 0), + ); + _core._finishCv(_stackLength); + _isFinished = true; + } + return Uint8List.fromList(Uint8List.view(_core._chainingValue.buffer)); + } + + /// Starts an empty message, reusing scratch storage. + void reset() { + _blockLength = 0; + _blocksCompressed = 0; + _chunkCounter = 0; + _stackLength = 0; + _isFinished = false; + _core._resetCv(); + } + + void _compressBlock(Uint32List words, int offset) { + var endsChunk = + _blocksCompressed == + _Blake3Base._chunkSizeInBytes ~/ _Blake3Base._blockSizeInBytes - 1; + _core._compress( + _core._chainingValue, + words, + offset, + _chunkCounter, + _Blake3Base._blockSizeInBytes, + (_blocksCompressed == 0 ? _chunkStart : 0) | (endsChunk ? _chunkEnd : 0), + ); + if (endsChunk) { + _chunkCounter++; + _stackLength = _core._pushCv(_chunkCounter, _stackLength); + _blocksCompressed = 0; + _core._resetCv(); + } else { + _blocksCompressed++; + } + } +}
diff --git a/pkg/analyzer/test/src/summary/api_signature_test.dart b/pkg/analyzer/test/src/summary/api_signature_test.dart index 47dde02..d7fb52a 100644 --- a/pkg/analyzer/test/src/summary/api_signature_test.dart +++ b/pkg/analyzer/test/src/summary/api_signature_test.dart
@@ -2,15 +2,25 @@ // 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:math'; +import 'dart:typed_data'; + +import 'package:analyzer/dart/analysis/features.dart'; +import 'package:analyzer/src/binary/binary_reader.dart'; +import 'package:analyzer/src/binary/binary_writer.dart'; import 'package:analyzer/src/summary/api_signature.dart'; import 'package:convert/convert.dart'; -import 'package:crypto/crypto.dart'; +import 'package:crypto/crypto.dart' show md5; +import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; +import '../utilities/hash/blake3_reference.dart'; + main() { defineReflectiveSuite(() { defineReflectiveTests(ApiSignatureTest); + defineReflectiveTests(Blake3ApiSignatureTest); }); } @@ -93,3 +103,328 @@ checkBytes(expectedResult); } } + +@reflectiveTest +class Blake3ApiSignatureTest { + void checkSignature(Blake3ApiSignature signature, ApiSignature encoding) { + var expected = referenceBlake3(encoding.getBytes_forDebug()); + expect(signature.toByteList(), expected); + expect(signature.toHex(), hex.encode(expected)); + expect(signature.toUint32List().buffer.asUint8List(), expected); + var hash = signature.toHash(); + expect(hash.toString(), hex.encode(expected)); + var writer = BinaryWriter(); + hash.write(writer); + var restored = Hash.read(BinaryReader(writer.takeBytes())); + expect(restored, hash); + expect(restored.hashCode, hash.hashCode); + } + + void test_addBytes_bufferBoundaries() { + for (var prefix in [0, 1, 3, 4, 59, 60, 61, 63, 64, 65]) { + for (var length in [0, 1, 3, 4, 63, 64, 65, 127, 128, 1025, 4097]) { + var input = _bytes(length); + var signature = Blake3ApiSignature() + ..addBytes(_bytes(prefix)) + ..addBytes(input) + ..addInt(0x12345678) + ..addBytes(input) + ..addBytes(_bytes(65)); + var encoding = ApiSignature.unversioned() + ..addBytes(_bytes(prefix)) + ..addBytes(input) + ..addInt(0x12345678) + ..addBytes(input) + ..addBytes(_bytes(65)); + input.fillRange(0, input.length, 0); + checkSignature(signature, encoding); + } + } + } + + void test_addBytes_interleavedPrimitives() { + for (var prefix in [0, 1, 3, 4, 55, 56, 57, 60, 61, 63, 64, 65]) { + for (var length in [0, 1, 63, 64, 65, 1023, 1024, 1025, 4092, 4096]) { + var bytes = _bytes(length); + var signature = Blake3ApiSignature() + ..addBytes(_bytes(prefix)) + ..addInt(0x12345678) + ..addDouble(1 / 3) + ..addBytes(bytes) + ..addBool(true) + ..addBytes(Uint8List(0)); + var encoding = ApiSignature.unversioned() + ..addBytes(_bytes(prefix)) + ..addInt(0x12345678) + ..addDouble(1 / 3) + ..addBytes(bytes) + ..addBool(true) + ..addBytes([]); + checkSignature(signature, encoding); + } + } + } + + void test_addBytes_largeAndFragmented() { + var bytes = _bytes(65537); + var encoding = ApiSignature.unversioned()..addBytes(bytes); + for (var size in [1, 3, 63, 64, 65, 1024, 4096, 65537]) { + var signature = Blake3ApiSignature(); + for (var start = 0; start < bytes.length; start += size) { + signature.addBytes( + Uint8List.sublistView(bytes, start, min(start + size, bytes.length)), + ); + } + checkSignature(signature, encoding); + } + var large = _bytes(1024 * 1024); + checkSignature( + Blake3ApiSignature()..addBytes(large), + ApiSignature.unversioned()..addBytes(large), + ); + } + + void test_addBytes_largeViewsAfterPartialBuffers() { + for (var prefix in [0, 1, 2, 3, 4095, 4096, 4097]) { + for (var offset = 0; offset < 4; offset++) { + for (var length in [4096, 4097, 8192, 16385]) { + var input = Uint8List.sublistView(_bytes(length + offset), offset); + var signature = Blake3ApiSignature() + ..addBytes(_bytes(prefix)) + ..addBytes(input.asUnmodifiableView()) + ..addBool(true) + ..addBytes(input); + var encoding = ApiSignature.unversioned() + ..addBytes(_bytes(prefix)) + ..addBytes(input) + ..addBool(true) + ..addBytes(input); + input.fillRange(0, input.length, 0); + checkSignature(signature, encoding); + } + } + } + } + + void test_addBytes_viewsAndOwnership() { + for (var length in [0, 3, 60, 64, 65, 1025, 4097]) { + for (var offset in [0, 1, 2, 3, 4]) { + var backing = _bytes(length + 8); + var before = Uint8List.fromList(backing); + var view = Uint8List.sublistView(backing, offset, offset + length); + var encoding = ApiSignature.unversioned()..addBytes(view); + var signature = Blake3ApiSignature() + ..addBytes(view.asUnmodifiableView()); + expect(backing, before); + backing.fillRange(0, backing.length, 0); + checkSignature(signature, encoding); + } + var input = _bytes(length); + var encoding = ApiSignature.unversioned()..addBytes(input); + var signature = Blake3ApiSignature()..addBytes(input); + input.fillRange(0, input.length, 0); + checkSignature(signature, encoding); + } + } + + void test_addCollections() { + var signature = Blake3ApiSignature(); + var encoding = ApiSignature.unversioned(); + var features = FeatureSet.latestLanguageVersion(); + var version = Version(3, 11, 2); + var entries = [MapEntry('a', 1), MapEntry('ø', -1)]; + signature + ..addFeatureSet(features) + ..addLanguageVersion(version) + ..addList([1, -1, 3], signature.addInt) + ..addList<int>([], signature.addInt) + ..addStringList(['', 'abc', 'ø']) + ..addMapEntryList(entries, (key, value) { + signature.addString(key); + signature.addInt(value); + }); + encoding + ..addFeatureSet(features) + ..addLanguageVersion(version) + ..addList([1, -1, 3], encoding.addInt) + ..addList<int>([], encoding.addInt) + ..addStringList(['', 'abc', 'ø']) + ..addMapEntryList(entries, (key, value) { + encoding.addString(key); + encoding.addInt(value); + }); + var words = Uint32List.fromList([0, 1, 0xffffffff, 0x12345678]); + signature.addUint32List(words); + encoding.addUint32List(words); + // Match the existing API's whole-backing-buffer behavior for word views. + var view = Uint32List.sublistView(words, 1, 3); + signature.addUint32List(view); + encoding.addUint32List(view); + checkSignature(signature, encoding); + } + + void test_addPrimitives() { + var signature = Blake3ApiSignature(); + var encoding = ApiSignature.unversioned(); + for (var value in [true, false, true]) { + signature.addBool(value); + encoding.addBool(value); + } + for (var value in [0, 1, -1, 0x80000000, 0xffffffff, 0x100000001]) { + signature.addInt(value); + encoding.addInt(value); + } + for (var value in [0.0, -0.0, 1 / 3, -1.0, double.infinity]) { + signature.addDouble(value); + encoding.addDouble(value); + } + checkSignature(signature, encoding); + } + + void test_addPrimitives_bufferBoundaries() { + for (var prefix = 4088; prefix <= 4096; prefix++) { + for (var value in [-1, 0x100000001]) { + var signature = Blake3ApiSignature(); + var encoding = ApiSignature.unversioned(); + for (var i = 0; i < 3; i++) { + signature + ..addBytes(_bytes(prefix)) + ..addInt(value) + ..addDouble(-0.0) + ..addBool(true); + encoding + ..addBytes(_bytes(prefix)) + ..addInt(value) + ..addDouble(-0.0) + ..addBool(true); + } + checkSignature(signature, encoding); + } + checkSignature( + Blake3ApiSignature() + ..addBytes(_bytes(prefix)) + ..addDouble(1 / 3), + ApiSignature.unversioned() + ..addBytes(_bytes(prefix)) + ..addDouble(1 / 3), + ); + } + } + + void test_addString_bufferBoundaries() { + for (var prefix in [0, 1, 55, 56, 57, 60, 61, 63, 64, 4093]) { + var signature = Blake3ApiSignature()..addBytes(_bytes(prefix)); + var encoding = ApiSignature.unversioned()..addBytes(_bytes(prefix)); + for (var value in [ + '', + 'abc', + '\u0000\u007f', + 'øÐ–Я😀', + '\ud800', + 'a' * 63, + 'b' * 64, + 'c' * 65, + 'a' * 4096, + 'ø' * 2048, + ]) { + signature.addString(value); + encoding.addString(value); + } + checkSignature(signature, encoding); + } + } + + void test_addString_utf8_bufferBoundaries() { + var strings = [ + for (var length in [1022, 1023, 1024, 4091, 4092, 4093]) + for (var suffix in [ + '\u007f\u0080\u07ff\u0800\uffff', + '\ud800', + '\udc00', + '\ud800\ud800\udc00\udc00', + '😀Жø', + ]) + '${'a' * length}$suffix', + 'øÐ–😀\ud800a\udc00' * 4096, + ]; + var random = Random(42); + strings.add( + String.fromCharCodes( + List.generate(16384, (_) => random.nextInt(0x10000)), + ), + ); + for (var prefix in [0, 1, 4091, 4092, 4093]) { + var signature = Blake3ApiSignature()..addBytes(_bytes(prefix)); + var encoding = ApiSignature.unversioned()..addBytes(_bytes(prefix)); + for (var value in strings) { + signature.addString(value); + encoding.addString(value); + } + checkSignature(signature, encoding); + } + } + + void test_digest_finalizesInput() { + var finishers = <void Function(Blake3ApiSignature)>[ + (signature) { + signature.toByteList(); + }, + (signature) { + signature.toHash(); + }, + (signature) { + signature.toHex(); + }, + (signature) { + signature.toUint32List(); + }, + ]; + for (var finish in finishers) { + var signature = Blake3ApiSignature()..addString('done'); + finish(signature); + expect(() => signature.addBool(false), throwsStateError); + expect(() => signature.addBytes(Uint8List(0)), throwsStateError); + expect(() => signature.addBytes(_bytes(4096)), throwsStateError); + expect(() => signature.addDouble(0), throwsStateError); + expect(() => signature.addInt(0), throwsStateError); + expect(() => signature.addString(''), throwsStateError); + expect( + () => signature.addList<int>([], signature.addInt), + throwsStateError, + ); + expect(() => signature.addStringList([]), throwsStateError); + expect(() => signature.addUint32List(Uint32List(0)), throwsStateError); + checkSignature(signature, ApiSignature.unversioned()..addString('done')); + } + } + + void test_digest_interleavedSignatures() { + var first = Blake3ApiSignature()..addBytes(_bytes(1025)); + var second = Blake3ApiSignature()..addString('second'); + first.addString('first'); + second.addBytes(_bytes(65)); + var encoding = ApiSignature.unversioned() + ..addBytes(_bytes(1025)) + ..addString('first'); + var saved = first.toHash(); + var expected = first.toByteList(); + first.toByteList().fillRange(0, 32, 0); + first.toUint32List().fillRange(0, 8, 0); + checkSignature( + second, + ApiSignature.unversioned() + ..addString('second') + ..addBytes(_bytes(65)), + ); + checkSignature(first, encoding); + expect(saved.toString(), hex.encode(expected)); + expect(first.toHash(), saved); + } + + void test_empty() { + checkSignature(Blake3ApiSignature(), ApiSignature.unversioned()); + } + + Uint8List _bytes(int length) => + Uint8List.fromList(List.generate(length, (i) => (i * 31 + 17) & 255)); +}
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart index 1f758f3..7e45cbb 100644 --- a/pkg/analyzer/test/src/summary/element_text.dart +++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -43,10 +43,24 @@ elementPrinter: elementPrinter, configuration: configuration, ); + if (configuration.combinedFragmentData case (:var element, :var data)) { + writer2.writeCombinedFragmentData(element, data); + } writer2.writeLibraryElement(library); } +/// The data that an element combines from its fragments. +enum CombinedFragmentData { + /// The constant initializer of a variable, or the default value of a + /// formal parameter. + constantInitializer, + metadata, +} + class ElementTextConfiguration { + /// See [withCombinedFragmentData]. + ({ElementImpl element, CombinedFragmentData data})? combinedFragmentData; + ElementPrinterConfiguration elementPrinterConfiguration = ElementPrinterConfiguration(); bool Function(Object) filter; @@ -118,6 +132,16 @@ }; } + /// Writes [data] of [element] before the library, first as [element] + /// combines it from its fragments, then for each fragment. + /// + /// It is written before anything else, so it is the first access, and the + /// text shows whether the fragments are read on demand. Only one kind of + /// data is written, because accessing other data could read the fragments. + void withCombinedFragmentData(Element element, CombinedFragmentData data) { + combinedFragmentData = (element: element as ElementImpl, data: data); + } + static bool _filterTrue(Object element) => true; } @@ -235,6 +259,71 @@ required super.configuration, }); + /// See [ElementTextConfiguration.withCombinedFragmentData]. + void writeCombinedFragmentData(ElementImpl e, CombinedFragmentData data) { + // Number the fragments in their order, without reading them. + for (var fragment in e.fragments) { + _idMap[fragment]; + } + + // The element combines the annotations of its fragments, so each + // annotation is written once, and then referenced by its id. + var annotationIds = Map<ElementAnnotation, String>.identity(); + void writeMetadata(Metadata metadata) { + var annotations = metadata.annotations; + if (annotations.isEmpty) { + return; + } + _sink.writelnWithIndent('metadata'); + _sink.withIndent(() { + for (var annotation in annotations) { + if (annotationIds[annotation] case var id?) { + _sink.writelnWithIndent(id); + } else { + var id = annotationIds[annotation] = + 'annotation_${annotationIds.length}'; + _sink.writelnWithIndent(id); + _sink.withIndent(() { + annotation as ElementAnnotationImpl; + _writeNode(annotation.annotationAst); + }); + } + } + }); + } + + _sink.writelnWithIndent('combinedFragmentData'); + _sink.withIndent(() { + _elementPrinter.writeNamedElement2('element', e); + _sink.writelnWithIndent('combined'); + _sink.withIndent(() { + switch (data) { + case CombinedFragmentData.constantInitializer: + _writeVariableElementConstantInitializer(e as VariableElementImpl); + case CombinedFragmentData.metadata: + writeMetadata(e.metadata); + } + }); + + _sink.writelnWithIndent('fragments'); + _sink.withIndent(() { + for (var fragment in e.fragments) { + _sink.writelnWithIndent(_idMap[fragment]); + _sink.withIndent(() { + switch (data) { + case CombinedFragmentData.constantInitializer: + _writeVariableFragmentInitializer( + fragment as VariableFragmentImpl, + ); + case CombinedFragmentData.metadata: + writeMetadata(fragment.metadata); + } + }); + } + }); + }); + } + void writeLibraryElement(LibraryElementImpl e) { expect(e.enclosingElement, isNull);
diff --git a/pkg/analyzer/test/src/summary/elements/class_test.dart b/pkg/analyzer/test/src/summary/elements/class_test.dart index 6a5fe24..541e3e4 100644 --- a/pkg/analyzer/test/src/summary/elements/class_test.dart +++ b/pkg/analyzer/test/src/summary/elements/class_test.dart
@@ -30704,6 +30704,90 @@ '''); } + test_field_augmentation_chain_instanceLateFinal_typed_hasConstConstructor() async { + var library = await buildLibrary(r''' +class A { + late final A foo = this; + const A(); +} + +augment class A { + augment late final A foo = this; +} +'''); + + checkElementText(library, r''' +library + reference: <testLibrary> + fragments + #F0 <testLibraryFragment> + element: <testLibrary> + classes + #F1 class A (nameOffset:6) (firstTokenOffset:0) (offset:6) + element: <testLibrary>::@class::A + nextFragment: #F2 + fields + #F3 hasInitializer isFinal isLate isOriginDeclaration foo (nameOffset:25) (firstTokenOffset:25) (offset:25) + element: <testLibrary>::@class::A::@field::foo + initializer: expression_0 + ThisExpression + thisKeyword: this @31 + staticType: A + inducedGetter: #F4 + nextFragment: #F5 + constructors + #F6 isConst isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:39) (offset:45) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 45 + getters + #F4 isComplete isOriginVariable foo (nameOffset:<null>) (firstTokenOffset:<null>) (offset:25) + element: <testLibrary>::@class::A::@getter::foo + inducingVariable: #F3 + nextFragment: #F7 + #F2 isAugmentation class A (nameOffset:67) (firstTokenOffset:53) (offset:67) + element: <testLibrary>::@class::A + previousFragment: #F1 + fields + #F5 hasInitializer isAugmentation isFinal isLate isOriginDeclaration foo (nameOffset:94) (firstTokenOffset:94) (offset:94) + element: <testLibrary>::@class::A::@field::foo + initializer: expression_1 + ThisExpression + thisKeyword: this @100 + staticType: A + inducedGetter: #F7 + previousFragment: #F3 + getters + #F7 isAugmentation isComplete isOriginVariable foo (nameOffset:<null>) (firstTokenOffset:<null>) (offset:94) + element: <testLibrary>::@class::A::@getter::foo + inducingVariable: #F5 + previousFragment: #F4 + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A + firstFragment: #F1 + fields + hasInitializer isFinal isLate isOriginDeclaration foo + reference: <testLibrary>::@class::A::@field::foo + firstFragment: #F3 + type: A + constantInitializer + fragment: #F5 + expression: expression_1 + getter: <testLibrary>::@class::A::@getter::foo + constructors + isConst isOriginDeclaration new + reference: <testLibrary>::@class::A::@constructor::new + firstFragment: #F6 + getters + isOriginVariable foo + reference: <testLibrary>::@class::A::@getter::foo + firstFragment: #F4 + returnType: A + variable: <testLibrary>::@class::A::@field::foo +'''); + } + test_field_augmentation_chain_noIntroductoryDeclaration() async { var library = await buildLibrary(r''' class A {} @@ -32495,6 +32579,76 @@ '''); } + test_field_final_hasInitializer_hasConstPrimaryConstructor() async { + var library = await buildLibrary(r''' +class const A(int x) { + final int foo = x; +} +'''); + + checkElementText(library, r''' +library + reference: <testLibrary> + fragments + #F0 <testLibraryFragment> + element: <testLibrary> + classes + #F1 class A (nameOffset:12) (firstTokenOffset:0) (offset:12) + element: <testLibrary>::@class::A + fields + #F2 hasInitializer isFinal isOriginDeclaration foo (nameOffset:35) (firstTokenOffset:35) (offset:35) + element: <testLibrary>::@class::A::@field::foo + initializer: expression_0 + UnqualifiedNameExpression + name: x @41 + resolution: VariableReadResolution + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + type: int + staticType: int + inducedGetter: #F3 + constructors + #F4 isConst isOriginDeclaration isPrimary new (nameOffset:<null>) (firstTokenOffset:6) (offset:12) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 12 + primaryHeaderCodeRange: 13 + 7 + formalParameters + #F5 requiredPositional isOriginDeclaration x (nameOffset:18) (firstTokenOffset:14) (offset:18) + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + getters + #F3 isComplete isOriginVariable foo (nameOffset:<null>) (firstTokenOffset:<null>) (offset:35) + element: <testLibrary>::@class::A::@getter::foo + inducingVariable: #F2 + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A + firstFragment: #F1 + fields + hasInitializer isFinal isOriginDeclaration foo + reference: <testLibrary>::@class::A::@field::foo + firstFragment: #F2 + type: int + constantInitializer + fragment: #F2 + expression: expression_0 + getter: <testLibrary>::@class::A::@getter::foo + constructors + isConst isOriginDeclaration isPrimary new + reference: <testLibrary>::@class::A::@constructor::new + firstFragment: #F4 + formalParameters + #E0 requiredPositional x + firstFragment: #F5 + type: int + getters + isOriginVariable foo + reference: <testLibrary>::@class::A::@getter::foo + firstFragment: #F3 + returnType: int + variable: <testLibrary>::@class::A::@field::foo +'''); + } + test_field_final_hasInitializer_noConstConstructor() async { var library = await buildLibrary(r''' class C {
diff --git a/pkg/analyzer/test/src/summary/elements/default_value_test.dart b/pkg/analyzer/test/src/summary/elements/default_value_test.dart index 0aaab22..729f144 100644 --- a/pkg/analyzer/test/src/summary/elements/default_value_test.dart +++ b/pkg/analyzer/test/src/summary/elements/default_value_test.dart
@@ -6,6 +6,7 @@ import 'package:test_reflective_loader/test_reflective_loader.dart'; import '../../dart/resolution/node_text_expectations.dart'; +import '../element_text.dart'; import '../elements_base.dart'; main() { @@ -17,7 +18,7 @@ } abstract class DefaultValueElementTest extends ElementsBaseTest { - test_defaultValue_augmentation_constructor() async { + test_defaultValue_augmentation_constructor_inAugmentation() async { var library = await buildLibrary(r''' const zero = 0; @@ -29,47 +30,63 @@ augment A([int x = zero]); } '''); + // Check the default value without asking any other properties. + var x = library.getClass('A')!.unnamedConstructor!.formalParameters.single; + configuration.withCombinedFragmentData( + x, + CombinedFragmentData.constantInitializer, + ); checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + combined + constantInitializer + fragment: #F1 + expression: expression_0 + UnqualifiedNameExpression + name: zero @83 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::zero + invokeType: int Function() + type: int + staticType: int + fragments + #F0 + #F1 + initializer: expression_0 library reference: <testLibrary> fragments - #F0 <testLibraryFragment> + #F2 <testLibraryFragment> element: <testLibrary> classes - #F1 class A (nameOffset:23) (firstTokenOffset:17) (offset:23) + #F3 class A (nameOffset:23) (firstTokenOffset:17) (offset:23) element: <testLibrary>::@class::A - nextFragment: #F2 + nextFragment: #F4 constructors - #F3 isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:29) (offset:29) + #F5 isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:29) (offset:29) element: <testLibrary>::@class::A::@constructor::new typeName: A typeNameOffset: 29 formalParameters - #F4 optionalPositional isOriginDeclaration x (nameOffset:36) (firstTokenOffset:32) (offset:36) + #F0 optionalPositional isOriginDeclaration x (nameOffset:36) (firstTokenOffset:32) (offset:36) element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x - nextFragment: #F5 + nextFragment: #F1 nextFragment: #F6 - #F2 isAugmentation class A (nameOffset:58) (firstTokenOffset:44) (offset:58) + #F4 isAugmentation class A (nameOffset:58) (firstTokenOffset:44) (offset:58) element: <testLibrary>::@class::A - previousFragment: #F1 + previousFragment: #F3 constructors #F6 isAugmentation isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:64) (offset:72) element: <testLibrary>::@class::A::@constructor::new typeName: A typeNameOffset: 72 formalParameters - #F5 optionalPositional isOriginDeclaration x (nameOffset:79) (firstTokenOffset:75) (offset:79) + #F1 optionalPositional isOriginDeclaration x (nameOffset:79) (firstTokenOffset:75) (offset:79) element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x initializer: expression_0 - UnqualifiedNameExpression - name: zero @83 - resolution: GetterInvocationResolution - element: <testLibrary>::@getter::zero - invokeType: int Function() - type: int - staticType: int - previousFragment: #F4 - previousFragment: #F3 + previousFragment: #F0 + previousFragment: #F5 topLevelVariables #F7 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic zero (nameOffset:6) (firstTokenOffset:6) (offset:6) element: <testLibrary>::@topLevelVariable::zero @@ -85,17 +102,17 @@ classes isSimplyBounded class A reference: <testLibrary>::@class::A - firstFragment: #F1 + firstFragment: #F3 constructors isOriginDeclaration new reference: <testLibrary>::@class::A::@constructor::new - firstFragment: #F3 + firstFragment: #F5 formalParameters #E0 optionalPositional hasDefaultValue x - firstFragment: #F4 + firstFragment: #F0 type: int constantInitializer - fragment: #F5 + fragment: #F1 expression: expression_0 topLevelVariables hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer zero @@ -115,86 +132,177 @@ '''); } - test_defaultValue_augmentation_function() async { + test_defaultValue_augmentation_constructor_inBoth() async { var library = await buildLibrary(r''' -const zero = 0; +class A { + A([int x = 1]); +} -void foo([int x]); - -augment void foo([int x = zero]) {} +augment class A { + augment A([int x = 2]); +} '''); + // Check the default value without asking any other properties. + var x = library.getClass('A')!.unnamedConstructor!.formalParameters.single; + configuration.withCombinedFragmentData( + x, + CombinedFragmentData.constantInitializer, + ); checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + combined + constantInitializer + fragment: #F1 + expression: expression_0 + IntegerLiteral + literal: 2 @70 + staticType: int + fragments + #F0 + initializer: expression_1 + IntegerLiteral + literal: 1 @23 + staticType: int + #F1 + initializer: expression_0 library reference: <testLibrary> fragments - #F0 <testLibraryFragment> + #F2 <testLibraryFragment> element: <testLibrary> - topLevelVariables - #F1 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic zero (nameOffset:6) (firstTokenOffset:6) (offset:6) - element: <testLibrary>::@topLevelVariable::zero - initializer: expression_0 - IntegerLiteral - literal: 0 @13 - staticType: int - inducedGetter: #F2 - getters - #F2 isComplete isOriginVariable isStatic zero (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) - element: <testLibrary>::@getter::zero - inducingVariable: #F1 - functions - #F3 isOriginDeclaration isStatic foo (nameOffset:22) (firstTokenOffset:17) (offset:22) - element: <testLibrary>::@function::foo + classes + #F3 class A (nameOffset:6) (firstTokenOffset:0) (offset:6) + element: <testLibrary>::@class::A nextFragment: #F4 - formalParameters - #F5 optionalPositional isOriginDeclaration x (nameOffset:31) (firstTokenOffset:27) (offset:31) - element: <testLibrary>::@function::foo::@formalParameter::x + constructors + #F5 isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:12) (offset:12) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 12 + formalParameters + #F0 optionalPositional isOriginDeclaration x (nameOffset:19) (firstTokenOffset:15) (offset:19) + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + initializer: expression_1 + nextFragment: #F1 nextFragment: #F6 - #F4 isAugmentation isComplete isOriginDeclaration isStatic foo (nameOffset:50) (firstTokenOffset:37) (offset:50) - element: <testLibrary>::@function::foo + #F4 isAugmentation class A (nameOffset:45) (firstTokenOffset:31) (offset:45) + element: <testLibrary>::@class::A previousFragment: #F3 - formalParameters - #F6 optionalPositional isOriginDeclaration x (nameOffset:59) (firstTokenOffset:55) (offset:59) - element: <testLibrary>::@function::foo::@formalParameter::x - initializer: expression_1 - UnqualifiedNameExpression - name: zero @63 - resolution: GetterInvocationResolution - element: <testLibrary>::@getter::zero - invokeType: int Function() - type: int - staticType: int + constructors + #F6 isAugmentation isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:51) (offset:59) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 59 + formalParameters + #F1 optionalPositional isOriginDeclaration x (nameOffset:66) (firstTokenOffset:62) (offset:66) + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + initializer: expression_0 + previousFragment: #F0 previousFragment: #F5 - topLevelVariables - hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer zero - reference: <testLibrary>::@topLevelVariable::zero - firstFragment: #F1 - type: int - constantInitializer - fragment: #F1 - expression: expression_0 - getter: <testLibrary>::@getter::zero - getters - isOriginVariable isStatic zero - reference: <testLibrary>::@getter::zero - firstFragment: #F2 - returnType: int - variable: <testLibrary>::@topLevelVariable::zero - functions - isOriginDeclaration isStatic foo - reference: <testLibrary>::@function::foo + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A firstFragment: #F3 - formalParameters - #E0 optionalPositional hasDefaultValue x + constructors + isOriginDeclaration new + reference: <testLibrary>::@class::A::@constructor::new firstFragment: #F5 - type: int - constantInitializer - fragment: #F6 - expression: expression_1 - returnType: void + formalParameters + #E0 optionalPositional hasDefaultValue x + firstFragment: #F0 + type: int + constantInitializer + fragment: #F1 + expression: expression_0 '''); } - test_defaultValue_augmentation_method() async { + test_defaultValue_augmentation_constructor_inIntroductory() async { + var library = await buildLibrary(r''' +class A { + A([int x = 1]); +} + +augment class A { + augment A([int x]); +} +'''); + // Check the default value without asking any other properties, reaching + // the element via the augmentation, so the introductory fragment is not + // read. + var constructor = library.getClass('A')!.unnamedConstructor!; + var x = constructor.fragments.last.formalParameters.single.element; + configuration.withCombinedFragmentData( + x, + CombinedFragmentData.constantInitializer, + ); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + combined + constantInitializer + fragment: #F0 + expression: expression_0 + IntegerLiteral + literal: 1 @23 + staticType: int + fragments + #F0 + initializer: expression_0 + #F1 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + classes + #F3 class A (nameOffset:6) (firstTokenOffset:0) (offset:6) + element: <testLibrary>::@class::A + nextFragment: #F4 + constructors + #F5 isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:12) (offset:12) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 12 + formalParameters + #F0 optionalPositional isOriginDeclaration x (nameOffset:19) (firstTokenOffset:15) (offset:19) + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + initializer: expression_0 + nextFragment: #F1 + nextFragment: #F6 + #F4 isAugmentation class A (nameOffset:45) (firstTokenOffset:31) (offset:45) + element: <testLibrary>::@class::A + previousFragment: #F3 + constructors + #F6 isAugmentation isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:51) (offset:59) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 59 + formalParameters + #F1 optionalPositional isOriginDeclaration x (nameOffset:66) (firstTokenOffset:62) (offset:66) + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + previousFragment: #F0 + previousFragment: #F5 + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A + firstFragment: #F3 + constructors + isOriginDeclaration new + reference: <testLibrary>::@class::A::@constructor::new + firstFragment: #F5 + formalParameters + #E0 optionalPositional hasDefaultValue x + firstFragment: #F0 + type: int + constantInitializer + fragment: #F0 + expression: expression_0 +'''); + } + + test_defaultValue_augmentation_method_inAugmentation() async { var library = await buildLibrary(r''' const zero = 0; @@ -206,47 +314,63 @@ augment void foo([int x = zero]) {} } '''); + // Check the default value without asking any other properties. + var x = library.getClass('A')!.getMethod('foo')!.formalParameters.single; + configuration.withCombinedFragmentData( + x, + CombinedFragmentData.constantInitializer, + ); checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + combined + constantInitializer + fragment: #F1 + expression: expression_0 + UnqualifiedNameExpression + name: zero @97 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::zero + invokeType: int Function() + type: int + staticType: int + fragments + #F0 + #F1 + initializer: expression_0 library reference: <testLibrary> fragments - #F0 <testLibraryFragment> + #F2 <testLibraryFragment> element: <testLibrary> classes - #F1 class A (nameOffset:23) (firstTokenOffset:17) (offset:23) + #F3 class A (nameOffset:23) (firstTokenOffset:17) (offset:23) element: <testLibrary>::@class::A - nextFragment: #F2 + nextFragment: #F4 constructors - #F3 isOriginImplicitDefault new (nameOffset:<null>) (firstTokenOffset:<null>) (offset:23) + #F5 isOriginImplicitDefault new (nameOffset:<null>) (firstTokenOffset:<null>) (offset:23) element: <testLibrary>::@class::A::@constructor::new typeName: A methods - #F4 isAbstract isOriginDeclaration foo (nameOffset:34) (firstTokenOffset:29) (offset:34) + #F6 isAbstract isOriginDeclaration foo (nameOffset:34) (firstTokenOffset:29) (offset:34) element: <testLibrary>::@class::A::@method::foo - nextFragment: #F5 + nextFragment: #F7 formalParameters - #F6 optionalPositional isOriginDeclaration x (nameOffset:43) (firstTokenOffset:39) (offset:43) + #F0 optionalPositional isOriginDeclaration x (nameOffset:43) (firstTokenOffset:39) (offset:43) element: <testLibrary>::@class::A::@method::foo::@formalParameter::x - nextFragment: #F7 - #F2 isAugmentation class A (nameOffset:65) (firstTokenOffset:51) (offset:65) + nextFragment: #F1 + #F4 isAugmentation class A (nameOffset:65) (firstTokenOffset:51) (offset:65) element: <testLibrary>::@class::A - previousFragment: #F1 + previousFragment: #F3 methods - #F5 isAugmentation isComplete isOriginDeclaration foo (nameOffset:84) (firstTokenOffset:71) (offset:84) + #F7 isAugmentation isComplete isOriginDeclaration foo (nameOffset:84) (firstTokenOffset:71) (offset:84) element: <testLibrary>::@class::A::@method::foo - previousFragment: #F4 + previousFragment: #F6 formalParameters - #F7 optionalPositional isOriginDeclaration x (nameOffset:93) (firstTokenOffset:89) (offset:93) + #F1 optionalPositional isOriginDeclaration x (nameOffset:93) (firstTokenOffset:89) (offset:93) element: <testLibrary>::@class::A::@method::foo::@formalParameter::x initializer: expression_0 - UnqualifiedNameExpression - name: zero @97 - resolution: GetterInvocationResolution - element: <testLibrary>::@getter::zero - invokeType: int Function() - type: int - staticType: int - previousFragment: #F6 + previousFragment: #F0 topLevelVariables #F8 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic zero (nameOffset:6) (firstTokenOffset:6) (offset:6) element: <testLibrary>::@topLevelVariable::zero @@ -262,21 +386,21 @@ classes isSimplyBounded class A reference: <testLibrary>::@class::A - firstFragment: #F1 + firstFragment: #F3 constructors isOriginImplicitDefault new reference: <testLibrary>::@class::A::@constructor::new - firstFragment: #F3 + firstFragment: #F5 methods isOriginDeclaration foo reference: <testLibrary>::@class::A::@method::foo - firstFragment: #F4 + firstFragment: #F6 formalParameters #E0 optionalPositional hasDefaultValue x - firstFragment: #F6 + firstFragment: #F0 type: int constantInitializer - fragment: #F7 + fragment: #F1 expression: expression_0 returnType: void topLevelVariables @@ -297,6 +421,637 @@ '''); } + test_defaultValue_augmentation_method_inBoth() async { + var library = await buildLibrary(r''' +class A { + void foo([int x = 1]); +} + +augment class A { + augment void foo([int x = 2]) {} +} +'''); + // Check the default value without asking any other properties. + var x = library.getClass('A')!.getMethod('foo')!.formalParameters.single; + configuration.withCombinedFragmentData( + x, + CombinedFragmentData.constantInitializer, + ); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + combined + constantInitializer + fragment: #F1 + expression: expression_0 + IntegerLiteral + literal: 2 @84 + staticType: int + fragments + #F0 + initializer: expression_1 + IntegerLiteral + literal: 1 @30 + staticType: int + #F1 + initializer: expression_0 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + classes + #F3 class A (nameOffset:6) (firstTokenOffset:0) (offset:6) + element: <testLibrary>::@class::A + nextFragment: #F4 + constructors + #F5 isOriginImplicitDefault new (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + methods + #F6 isAbstract isOriginDeclaration foo (nameOffset:17) (firstTokenOffset:12) (offset:17) + element: <testLibrary>::@class::A::@method::foo + nextFragment: #F7 + formalParameters + #F0 optionalPositional isOriginDeclaration x (nameOffset:26) (firstTokenOffset:22) (offset:26) + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + initializer: expression_1 + nextFragment: #F1 + #F4 isAugmentation class A (nameOffset:52) (firstTokenOffset:38) (offset:52) + element: <testLibrary>::@class::A + previousFragment: #F3 + methods + #F7 isAugmentation isComplete isOriginDeclaration foo (nameOffset:71) (firstTokenOffset:58) (offset:71) + element: <testLibrary>::@class::A::@method::foo + previousFragment: #F6 + formalParameters + #F1 optionalPositional isOriginDeclaration x (nameOffset:80) (firstTokenOffset:76) (offset:80) + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + initializer: expression_0 + previousFragment: #F0 + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A + firstFragment: #F3 + constructors + isOriginImplicitDefault new + reference: <testLibrary>::@class::A::@constructor::new + firstFragment: #F5 + methods + isOriginDeclaration foo + reference: <testLibrary>::@class::A::@method::foo + firstFragment: #F6 + formalParameters + #E0 optionalPositional hasDefaultValue x + firstFragment: #F0 + type: int + constantInitializer + fragment: #F1 + expression: expression_0 + returnType: void +'''); + } + + test_defaultValue_augmentation_method_inIntroductory() async { + var library = await buildLibrary(r''' +class A { + void foo([int x = 1]); +} + +augment class A { + augment void foo([int x]) {} +} +'''); + // Check the default value without asking any other properties, reaching + // the element via the augmentation, so the introductory fragment is not + // read. + var foo = library.getClass('A')!.getMethod('foo')!; + var x = foo.fragments.last.formalParameters.single.element; + configuration.withCombinedFragmentData( + x, + CombinedFragmentData.constantInitializer, + ); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + combined + constantInitializer + fragment: #F0 + expression: expression_0 + IntegerLiteral + literal: 1 @30 + staticType: int + fragments + #F0 + initializer: expression_0 + #F1 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + classes + #F3 class A (nameOffset:6) (firstTokenOffset:0) (offset:6) + element: <testLibrary>::@class::A + nextFragment: #F4 + constructors + #F5 isOriginImplicitDefault new (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + methods + #F6 isAbstract isOriginDeclaration foo (nameOffset:17) (firstTokenOffset:12) (offset:17) + element: <testLibrary>::@class::A::@method::foo + nextFragment: #F7 + formalParameters + #F0 optionalPositional isOriginDeclaration x (nameOffset:26) (firstTokenOffset:22) (offset:26) + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + initializer: expression_0 + nextFragment: #F1 + #F4 isAugmentation class A (nameOffset:52) (firstTokenOffset:38) (offset:52) + element: <testLibrary>::@class::A + previousFragment: #F3 + methods + #F7 isAugmentation isComplete isOriginDeclaration foo (nameOffset:71) (firstTokenOffset:58) (offset:71) + element: <testLibrary>::@class::A::@method::foo + previousFragment: #F6 + formalParameters + #F1 optionalPositional isOriginDeclaration x (nameOffset:80) (firstTokenOffset:76) (offset:80) + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + previousFragment: #F0 + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A + firstFragment: #F3 + constructors + isOriginImplicitDefault new + reference: <testLibrary>::@class::A::@constructor::new + firstFragment: #F5 + methods + isOriginDeclaration foo + reference: <testLibrary>::@class::A::@method::foo + firstFragment: #F6 + formalParameters + #E0 optionalPositional hasDefaultValue x + firstFragment: #F0 + type: int + constantInitializer + fragment: #F0 + expression: expression_0 + returnType: void +'''); + } + + test_defaultValue_augmentation_setter_inAugmentation() async { + var library = await buildLibrary(r''' +set foo([int x]); + +augment set foo([int x = 2]) {} +'''); + // Check the default value without asking any other properties. + var x = library.getSetter('foo')!.formalParameters.single; + configuration.withCombinedFragmentData( + x, + CombinedFragmentData.constantInitializer, + ); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@setter::foo::@formalParameter::x + combined + constantInitializer + fragment: #F1 + expression: expression_0 + IntegerLiteral + literal: 2 @44 + staticType: int + fragments + #F0 + #F1 + initializer: expression_0 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + topLevelVariables + #F3 isOriginGetterSetter isStatic foo (nameOffset:<null>) (firstTokenOffset:<null>) (offset:4) + element: <testLibrary>::@topLevelVariable::foo + setters + #F4 hasImplicitReturnType isOriginDeclaration isStatic foo (nameOffset:4) (firstTokenOffset:0) (offset:4) + element: <testLibrary>::@setter::foo + formalParameters + #F0 optionalPositional isOriginDeclaration x (nameOffset:13) (firstTokenOffset:9) (offset:13) + element: <testLibrary>::@setter::foo::@formalParameter::x + nextFragment: #F1 + nextFragment: #F5 + #F5 hasImplicitReturnType isAugmentation isComplete isOriginDeclaration isStatic foo (nameOffset:31) (firstTokenOffset:19) (offset:31) + element: <testLibrary>::@setter::foo + formalParameters + #F1 optionalPositional isOriginDeclaration x (nameOffset:40) (firstTokenOffset:36) (offset:40) + element: <testLibrary>::@setter::foo::@formalParameter::x + initializer: expression_0 + previousFragment: #F0 + previousFragment: #F4 + topLevelVariables + isOriginGetterSetter isStatic foo + reference: <testLibrary>::@topLevelVariable::foo + firstFragment: #F3 + type: int + setter: <testLibrary>::@setter::foo + setters + hasImplicitReturnType isOriginDeclaration isStatic foo + reference: <testLibrary>::@setter::foo + firstFragment: #F4 + formalParameters + #E0 optionalPositional hasDefaultValue x + firstFragment: #F0 + type: int + constantInitializer + fragment: #F1 + expression: expression_0 + returnType: void + variable: <testLibrary>::@topLevelVariable::foo +'''); + } + + test_defaultValue_augmentation_setter_inBoth() async { + var library = await buildLibrary(r''' +set foo([int x = 1]); + +augment set foo([int x = 2]) {} +'''); + // Check the default value without asking any other properties. + var x = library.getSetter('foo')!.formalParameters.single; + configuration.withCombinedFragmentData( + x, + CombinedFragmentData.constantInitializer, + ); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@setter::foo::@formalParameter::x + combined + constantInitializer + fragment: #F1 + expression: expression_0 + IntegerLiteral + literal: 2 @48 + staticType: int + fragments + #F0 + initializer: expression_1 + IntegerLiteral + literal: 1 @17 + staticType: int + #F1 + initializer: expression_0 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + topLevelVariables + #F3 isOriginGetterSetter isStatic foo (nameOffset:<null>) (firstTokenOffset:<null>) (offset:4) + element: <testLibrary>::@topLevelVariable::foo + setters + #F4 hasImplicitReturnType isOriginDeclaration isStatic foo (nameOffset:4) (firstTokenOffset:0) (offset:4) + element: <testLibrary>::@setter::foo + formalParameters + #F0 optionalPositional isOriginDeclaration x (nameOffset:13) (firstTokenOffset:9) (offset:13) + element: <testLibrary>::@setter::foo::@formalParameter::x + initializer: expression_1 + nextFragment: #F1 + nextFragment: #F5 + #F5 hasImplicitReturnType isAugmentation isComplete isOriginDeclaration isStatic foo (nameOffset:35) (firstTokenOffset:23) (offset:35) + element: <testLibrary>::@setter::foo + formalParameters + #F1 optionalPositional isOriginDeclaration x (nameOffset:44) (firstTokenOffset:40) (offset:44) + element: <testLibrary>::@setter::foo::@formalParameter::x + initializer: expression_0 + previousFragment: #F0 + previousFragment: #F4 + topLevelVariables + isOriginGetterSetter isStatic foo + reference: <testLibrary>::@topLevelVariable::foo + firstFragment: #F3 + type: int + setter: <testLibrary>::@setter::foo + setters + hasImplicitReturnType isOriginDeclaration isStatic foo + reference: <testLibrary>::@setter::foo + firstFragment: #F4 + formalParameters + #E0 optionalPositional hasDefaultValue x + firstFragment: #F0 + type: int + constantInitializer + fragment: #F1 + expression: expression_0 + returnType: void + variable: <testLibrary>::@topLevelVariable::foo +'''); + } + + test_defaultValue_augmentation_setter_inIntroductory() async { + var library = await buildLibrary(r''' +set foo([int x = 1]); + +augment set foo([int x]) {} +'''); + // Check the default value without asking any other properties, reaching + // the element via the augmentation, so the introductory fragment is not + // read. + var foo = library.getSetter('foo')!; + var x = foo.fragments.last.formalParameters.single.element; + configuration.withCombinedFragmentData( + x, + CombinedFragmentData.constantInitializer, + ); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@setter::foo::@formalParameter::x + combined + constantInitializer + fragment: #F0 + expression: expression_0 + IntegerLiteral + literal: 1 @17 + staticType: int + fragments + #F0 + initializer: expression_0 + #F1 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + topLevelVariables + #F3 isOriginGetterSetter isStatic foo (nameOffset:<null>) (firstTokenOffset:<null>) (offset:4) + element: <testLibrary>::@topLevelVariable::foo + setters + #F4 hasImplicitReturnType isOriginDeclaration isStatic foo (nameOffset:4) (firstTokenOffset:0) (offset:4) + element: <testLibrary>::@setter::foo + formalParameters + #F0 optionalPositional isOriginDeclaration x (nameOffset:13) (firstTokenOffset:9) (offset:13) + element: <testLibrary>::@setter::foo::@formalParameter::x + initializer: expression_0 + nextFragment: #F1 + nextFragment: #F5 + #F5 hasImplicitReturnType isAugmentation isComplete isOriginDeclaration isStatic foo (nameOffset:35) (firstTokenOffset:23) (offset:35) + element: <testLibrary>::@setter::foo + formalParameters + #F1 optionalPositional isOriginDeclaration x (nameOffset:44) (firstTokenOffset:40) (offset:44) + element: <testLibrary>::@setter::foo::@formalParameter::x + previousFragment: #F0 + previousFragment: #F4 + topLevelVariables + isOriginGetterSetter isStatic foo + reference: <testLibrary>::@topLevelVariable::foo + firstFragment: #F3 + type: int + setter: <testLibrary>::@setter::foo + setters + hasImplicitReturnType isOriginDeclaration isStatic foo + reference: <testLibrary>::@setter::foo + firstFragment: #F4 + formalParameters + #E0 optionalPositional hasDefaultValue x + firstFragment: #F0 + type: int + constantInitializer + fragment: #F0 + expression: expression_0 + returnType: void + variable: <testLibrary>::@topLevelVariable::foo +'''); + } + + test_defaultValue_augmentation_topLevelFunction_inAugmentation() async { + var library = await buildLibrary(r''' +const zero = 0; + +void foo([int x]); + +augment void foo([int x = zero]) {} +'''); + // Check the default value without asking any other properties. + var x = library.getTopLevelFunction('foo')!.formalParameters.single; + configuration.withCombinedFragmentData( + x, + CombinedFragmentData.constantInitializer, + ); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@function::foo::@formalParameter::x + combined + constantInitializer + fragment: #F1 + expression: expression_0 + UnqualifiedNameExpression + name: zero @63 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::zero + invokeType: int Function() + type: int + staticType: int + fragments + #F0 + #F1 + initializer: expression_0 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + topLevelVariables + #F3 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic zero (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::zero + initializer: expression_1 + IntegerLiteral + literal: 0 @13 + staticType: int + inducedGetter: #F4 + getters + #F4 isComplete isOriginVariable isStatic zero (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::zero + inducingVariable: #F3 + functions + #F5 isOriginDeclaration isStatic foo (nameOffset:22) (firstTokenOffset:17) (offset:22) + element: <testLibrary>::@function::foo + nextFragment: #F6 + formalParameters + #F0 optionalPositional isOriginDeclaration x (nameOffset:31) (firstTokenOffset:27) (offset:31) + element: <testLibrary>::@function::foo::@formalParameter::x + nextFragment: #F1 + #F6 isAugmentation isComplete isOriginDeclaration isStatic foo (nameOffset:50) (firstTokenOffset:37) (offset:50) + element: <testLibrary>::@function::foo + previousFragment: #F5 + formalParameters + #F1 optionalPositional isOriginDeclaration x (nameOffset:59) (firstTokenOffset:55) (offset:59) + element: <testLibrary>::@function::foo::@formalParameter::x + initializer: expression_0 + previousFragment: #F0 + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer zero + reference: <testLibrary>::@topLevelVariable::zero + firstFragment: #F3 + type: int + constantInitializer + fragment: #F3 + expression: expression_1 + getter: <testLibrary>::@getter::zero + getters + isOriginVariable isStatic zero + reference: <testLibrary>::@getter::zero + firstFragment: #F4 + returnType: int + variable: <testLibrary>::@topLevelVariable::zero + functions + isOriginDeclaration isStatic foo + reference: <testLibrary>::@function::foo + firstFragment: #F5 + formalParameters + #E0 optionalPositional hasDefaultValue x + firstFragment: #F0 + type: int + constantInitializer + fragment: #F1 + expression: expression_0 + returnType: void +'''); + } + + test_defaultValue_augmentation_topLevelFunction_inBoth() async { + var library = await buildLibrary(r''' +void foo([int x = 1]); + +augment void foo([int x = 2]) {} +'''); + // Check the default value without asking any other properties. + var x = library.getTopLevelFunction('foo')!.formalParameters.single; + configuration.withCombinedFragmentData( + x, + CombinedFragmentData.constantInitializer, + ); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@function::foo::@formalParameter::x + combined + constantInitializer + fragment: #F1 + expression: expression_0 + IntegerLiteral + literal: 2 @50 + staticType: int + fragments + #F0 + initializer: expression_1 + IntegerLiteral + literal: 1 @18 + staticType: int + #F1 + initializer: expression_0 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + functions + #F3 isOriginDeclaration isStatic foo (nameOffset:5) (firstTokenOffset:0) (offset:5) + element: <testLibrary>::@function::foo + nextFragment: #F4 + formalParameters + #F0 optionalPositional isOriginDeclaration x (nameOffset:14) (firstTokenOffset:10) (offset:14) + element: <testLibrary>::@function::foo::@formalParameter::x + initializer: expression_1 + nextFragment: #F1 + #F4 isAugmentation isComplete isOriginDeclaration isStatic foo (nameOffset:37) (firstTokenOffset:24) (offset:37) + element: <testLibrary>::@function::foo + previousFragment: #F3 + formalParameters + #F1 optionalPositional isOriginDeclaration x (nameOffset:46) (firstTokenOffset:42) (offset:46) + element: <testLibrary>::@function::foo::@formalParameter::x + initializer: expression_0 + previousFragment: #F0 + functions + isOriginDeclaration isStatic foo + reference: <testLibrary>::@function::foo + firstFragment: #F3 + formalParameters + #E0 optionalPositional hasDefaultValue x + firstFragment: #F0 + type: int + constantInitializer + fragment: #F1 + expression: expression_0 + returnType: void +'''); + } + + test_defaultValue_augmentation_topLevelFunction_inIntroductory() async { + var library = await buildLibrary(r''' +void foo([int x = 1]); + +augment void foo([int x]) {} +'''); + // Check the default value without asking any other properties, reaching + // the element via the augmentation, so the introductory fragment is not + // read. + var foo = library.getTopLevelFunction('foo')!; + var x = foo.fragments.last.formalParameters.single.element; + configuration.withCombinedFragmentData( + x, + CombinedFragmentData.constantInitializer, + ); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@function::foo::@formalParameter::x + combined + constantInitializer + fragment: #F0 + expression: expression_0 + IntegerLiteral + literal: 1 @18 + staticType: int + fragments + #F0 + initializer: expression_0 + #F1 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + functions + #F3 isOriginDeclaration isStatic foo (nameOffset:5) (firstTokenOffset:0) (offset:5) + element: <testLibrary>::@function::foo + nextFragment: #F4 + formalParameters + #F0 optionalPositional isOriginDeclaration x (nameOffset:14) (firstTokenOffset:10) (offset:14) + element: <testLibrary>::@function::foo::@formalParameter::x + initializer: expression_0 + nextFragment: #F1 + #F4 isAugmentation isComplete isOriginDeclaration isStatic foo (nameOffset:37) (firstTokenOffset:24) (offset:37) + element: <testLibrary>::@function::foo + previousFragment: #F3 + formalParameters + #F1 optionalPositional isOriginDeclaration x (nameOffset:46) (firstTokenOffset:42) (offset:46) + element: <testLibrary>::@function::foo::@formalParameter::x + previousFragment: #F0 + functions + isOriginDeclaration isStatic foo + reference: <testLibrary>::@function::foo + firstFragment: #F3 + formalParameters + #E0 optionalPositional hasDefaultValue x + firstFragment: #F0 + type: int + constantInitializer + fragment: #F0 + expression: expression_0 + returnType: void +'''); + } + test_defaultValue_eliminateTypeParameters() async { var library = await buildLibrary(r''' class A<T> { @@ -727,6 +1482,88 @@ '''); } + test_defaultValue_primaryConstructor_declaringFormalParameter() async { + var library = await buildLibrary(r''' +class A([final int foo = 42]); +'''); + // Check the default value without asking any other properties. + var field = library.getClass('A')!.getField('foo')!; + var foo = field.declaringFormalParameter!; + configuration.withCombinedFragmentData( + foo, + CombinedFragmentData.constantInitializer, + ); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::foo + combined + constantInitializer + fragment: #F0 + expression: expression_0 + IntegerLiteral + literal: 42 @25 + staticType: int + fragments + #F0 + initializer: expression_0 +library + reference: <testLibrary> + fragments + #F1 <testLibraryFragment> + element: <testLibrary> + classes + #F2 class A (nameOffset:6) (firstTokenOffset:0) (offset:6) + element: <testLibrary>::@class::A + fields + #F3 isFinal isOriginDeclaringFormalParameter foo (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@class::A::@field::foo + inducedGetter: #F4 + constructors + #F5 isComplete isOriginDeclaration isPrimary new (nameOffset:<null>) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 6 + primaryHeaderCodeRange: 7 + 22 + formalParameters + #F0 optionalPositional isDeclaring isFinal isOriginDeclaration this.foo (nameOffset:19) (firstTokenOffset:9) (offset:19) + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::foo + initializer: expression_0 + getters + #F4 isComplete isOriginVariable foo (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@class::A::@getter::foo + inducingVariable: #F3 + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A + firstFragment: #F2 + fields + isFinal isOriginDeclaringFormalParameter foo + reference: <testLibrary>::@class::A::@field::foo + firstFragment: #F3 + type: int + getter: <testLibrary>::@class::A::@getter::foo + declaringFormalParameter: <testLibrary>::@class::A::@constructor::new::@formalParameter::foo + constructors + isOriginDeclaration isPrimary new + reference: <testLibrary>::@class::A::@constructor::new + firstFragment: #F5 + formalParameters + #E0 optionalPositional hasDefaultValue isDeclaring isFinal this.foo + firstFragment: #F0 + type: int + constantInitializer + fragment: #F0 + expression: expression_0 + field: <testLibrary>::@class::A::@field::foo + getters + isOriginVariable foo + reference: <testLibrary>::@class::A::@getter::foo + firstFragment: #F4 + returnType: int + variable: <testLibrary>::@class::A::@field::foo +'''); + } + test_defaultValue_recordLiteral_named() async { var library = await buildLibrary(r''' void f({({int f1, bool f2}) x = (f1: 1, f2: true)}) {}
diff --git a/pkg/analyzer/test/src/summary/elements/enum_test.dart b/pkg/analyzer/test/src/summary/elements/enum_test.dart index 5723884..ca40801 100644 --- a/pkg/analyzer/test/src/summary/elements/enum_test.dart +++ b/pkg/analyzer/test/src/summary/elements/enum_test.dart
@@ -465,13 +465,13 @@ constructorReference: ConstructorReference2 typeReference: ConstructorTypeReference name: A @-1 - element: <null> - type: null - element: <null> + element: <testLibrary>::@enum::A + type: A + element: <testLibrary>::@enum::A::@constructor::new argumentList: ArgumentList leftParenthesis: ( @0 rightParenthesis: ) @0 - staticType: null + staticType: A inducedGetter: #F11 previousFragment: #F8 getters @@ -688,13 +688,13 @@ constructorReference: ConstructorReference2 typeReference: ConstructorTypeReference name: A @-1 - element: <null> - type: null - element: <null> + element: <testLibrary>::@enum::A + type: A + element: <testLibrary>::@enum::A::@constructor::new argumentList: ArgumentList leftParenthesis: ( @0 rightParenthesis: ) @0 - staticType: null + staticType: A inducedGetter: #F13 previousFragment: #F5 getters @@ -898,13 +898,13 @@ constructorReference: ConstructorReference2 typeReference: ConstructorTypeReference name: A @-1 - element: <null> - type: null - element: <null> + element: <testLibrary>::@enum::A + type: A + element: <testLibrary>::@enum::A::@constructor::new argumentList: ArgumentList leftParenthesis: ( @0 rightParenthesis: ) @0 - staticType: null + staticType: A inducedGetter: #F12 previousFragment: #F5 getters @@ -961,6 +961,185 @@ '''); } + test_constant_augmentation_chain_typeParameters_inferred() async { + var library = await buildLibrary(r''' +enum A<T> { + v1(0); + const A(T value); +} + +augment enum A<T> { + augment v1('a') +} +'''); + + checkElementText(library, r''' +library + reference: <testLibrary> + fragments + #F0 <testLibraryFragment> + element: <testLibrary> + enums + #F1 enum A (nameOffset:5) (firstTokenOffset:0) (offset:5) + element: <testLibrary>::@enum::A + nextFragment: #F2 + typeParameters + #F3 T (nameOffset:7) (firstTokenOffset:7) (offset:7) + element: #E0 T + nextFragment: #F4 + fields + #F5 hasImplicitType hasInitializer isConst isEnumConstant isOriginDeclaration isStatic v1 (nameOffset:14) (firstTokenOffset:14) (offset:14) + element: <testLibrary>::@enum::A::@field::v1 + initializer: expression_0 + ConstructorInvocation + constructorReference: ConstructorReference2 + typeReference: ConstructorTypeReference + name: A @-1 + element: <testLibrary>::@enum::A + type: A<int> + element: SubstitutedConstructorElementImpl + baseElement: <testLibrary>::@enum::A::@constructor::new + substitution: {T: int} + argumentList: ArgumentList + leftParenthesis: ( @16 + arguments2 + IntegerLiteral + literal: 0 @17 + staticType: int + rightParenthesis: ) @18 + staticType: A<int> + inducedGetter: #F6 + nextFragment: #F7 + #F8 isConst isOriginEnumValues isStatic values (nameOffset:<null>) (firstTokenOffset:<null>) (offset:5) + element: <testLibrary>::@enum::A::@field::values + initializer: expression_1 + ListLiteral + leftBracket: [ @0 + elements2 + UnqualifiedNameExpression + name: v1 @-1 + resolution: GetterInvocationResolution + element: <testLibrary>::@enum::A::@getter::v1 + invokeType: A<int> Function() + type: A<int> + staticType: A<int> + UnqualifiedNameExpression + name: v1 @-1 + resolution: GetterInvocationResolution + element: <testLibrary>::@enum::A::@getter::v1 + invokeType: A<int> Function() + type: A<int> + staticType: A<int> + elements(v1) + SimpleIdentifier + token: v1 @-1 + element: <testLibrary>::@enum::A::@getter::v1 + staticType: A<int> + SimpleIdentifier + token: v1 @-1 + element: <testLibrary>::@enum::A::@getter::v1 + staticType: A<int> + rightBracket: ] @0 + staticType: List<A<dynamic>> + inducedGetter: #F9 + constructors + #F10 isConst isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:23) (offset:29) + element: <testLibrary>::@enum::A::@constructor::new + typeName: A + typeNameOffset: 29 + formalParameters + #F11 requiredPositional isOriginDeclaration value (nameOffset:33) (firstTokenOffset:31) (offset:33) + element: <testLibrary>::@enum::A::@constructor::new::@formalParameter::value + getters + #F6 isComplete isOriginVariable isStatic v1 (nameOffset:<null>) (firstTokenOffset:<null>) (offset:14) + element: <testLibrary>::@enum::A::@getter::v1 + inducingVariable: #F5 + nextFragment: #F12 + #F9 isComplete isOriginVariable isStatic values (nameOffset:<null>) (firstTokenOffset:<null>) (offset:5) + element: <testLibrary>::@enum::A::@getter::values + inducingVariable: #F8 + #F2 isAugmentation enum A (nameOffset:57) (firstTokenOffset:44) (offset:57) + element: <testLibrary>::@enum::A + previousFragment: #F1 + typeParameters + #F4 T (nameOffset:59) (firstTokenOffset:59) (offset:59) + element: #E0 T + previousFragment: #F3 + fields + #F7 hasImplicitType hasInitializer isAugmentation isConst isEnumConstant isOriginDeclaration isStatic v1 (nameOffset:74) (firstTokenOffset:66) (offset:74) + element: <testLibrary>::@enum::A::@field::v1 + initializer: expression_2 + ConstructorInvocation + constructorReference: ConstructorReference2 + typeReference: ConstructorTypeReference + name: A @-1 + element: <testLibrary>::@enum::A + type: A<int> + element: SubstitutedConstructorElementImpl + baseElement: <testLibrary>::@enum::A::@constructor::new + substitution: {T: int} + argumentList: ArgumentList + leftParenthesis: ( @76 + arguments2 + SimpleStringLiteral + literal: 'a' @77 + rightParenthesis: ) @80 + staticType: A<int> + inducedGetter: #F12 + previousFragment: #F5 + getters + #F12 isAugmentation isComplete isOriginVariable isStatic v1 (nameOffset:<null>) (firstTokenOffset:<null>) (offset:74) + element: <testLibrary>::@enum::A::@getter::v1 + inducingVariable: #F7 + previousFragment: #F6 + enums + isSimplyBounded enum A + reference: <testLibrary>::@enum::A + firstFragment: #F1 + typeParameters + #E0 T + firstFragment: #F3 + supertype: Enum + fields + hasImplicitType hasInitializer isConst isEnumConstant isOriginDeclaration isStatic isTypeInferredFromInitializer v1 + reference: <testLibrary>::@enum::A::@field::v1 + firstFragment: #F5 + type: A<int> + constantInitializer + fragment: #F7 + expression: expression_2 + getter: <testLibrary>::@enum::A::@getter::v1 + isConst isOriginEnumValues isStatic values + reference: <testLibrary>::@enum::A::@field::values + firstFragment: #F8 + type: List<A<dynamic>> + constantInitializer + fragment: #F8 + expression: expression_1 + getter: <testLibrary>::@enum::A::@getter::values + constructors + hasEnclosingTypeParameterReference isConst isOriginDeclaration new + reference: <testLibrary>::@enum::A::@constructor::new + firstFragment: #F10 + formalParameters + #E1 requiredPositional value + firstFragment: #F11 + type: T + superConstructor: dart:core::@class::Enum::@constructor::new + getters + isOriginVariable isStatic v1 + reference: <testLibrary>::@enum::A::@getter::v1 + firstFragment: #F6 + returnType: A<int> + variable: <testLibrary>::@enum::A::@field::v1 + isOriginVariable isStatic values + reference: <testLibrary>::@enum::A::@getter::values + firstFragment: #F9 + returnType: List<A<dynamic>> + variable: <testLibrary>::@enum::A::@field::values +'''); + } + test_constant_augmentation_chain_withArguments() async { var library = await buildLibrary(r''' enum A { @@ -1096,17 +1275,17 @@ constructorReference: ConstructorReference2 typeReference: ConstructorTypeReference name: A @-1 - element: <null> - type: null - element: <null> + element: <testLibrary>::@enum::A + type: A + element: <testLibrary>::@enum::A::@constructor::new argumentList: ArgumentList leftParenthesis: ( @79 arguments2 IntegerLiteral literal: 3 @80 - staticType: null + staticType: int rightParenthesis: ) @81 - staticType: null + staticType: A inducedGetter: #F12 previousFragment: #F3 getters @@ -1172,6 +1351,242 @@ '''); } + test_constant_augmentation_chain_withArguments_unqualifiedName() async { + var library = await buildLibrary(r''' +const zero = 0; +const one = 1; + +enum A { + v1(zero); + const A(int value); +} + +augment enum A { + augment v1(one) +} +'''); + + checkElementText(library, r''' +library + reference: <testLibrary> + fragments + #F0 <testLibraryFragment> + element: <testLibrary> + enums + #F1 enum A (nameOffset:37) (firstTokenOffset:32) (offset:37) + element: <testLibrary>::@enum::A + nextFragment: #F2 + fields + #F3 hasImplicitType hasInitializer isConst isEnumConstant isOriginDeclaration isStatic v1 (nameOffset:43) (firstTokenOffset:43) (offset:43) + element: <testLibrary>::@enum::A::@field::v1 + initializer: expression_0 + ConstructorInvocation + constructorReference: ConstructorReference2 + typeReference: ConstructorTypeReference + name: A @-1 + element: <testLibrary>::@enum::A + type: A + element: <testLibrary>::@enum::A::@constructor::new + argumentList: ArgumentList + leftParenthesis: ( @45 + arguments2 + UnqualifiedNameExpression + name: zero @46 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::zero + invokeType: int Function() + type: int + staticType: int + arguments(v1) + SimpleIdentifier + token: zero @46 + element: <testLibrary>::@getter::zero + staticType: int + rightParenthesis: ) @50 + staticType: A + inducedGetter: #F4 + nextFragment: #F5 + #F6 isConst isOriginEnumValues isStatic values (nameOffset:<null>) (firstTokenOffset:<null>) (offset:37) + element: <testLibrary>::@enum::A::@field::values + initializer: expression_1 + ListLiteral + leftBracket: [ @0 + elements2 + UnqualifiedNameExpression + name: v1 @-1 + resolution: GetterInvocationResolution + element: <testLibrary>::@enum::A::@getter::v1 + invokeType: A Function() + type: A + staticType: A + UnqualifiedNameExpression + name: v1 @-1 + resolution: GetterInvocationResolution + element: <testLibrary>::@enum::A::@getter::v1 + invokeType: A Function() + type: A + staticType: A + elements(v1) + SimpleIdentifier + token: v1 @-1 + element: <testLibrary>::@enum::A::@getter::v1 + staticType: A + SimpleIdentifier + token: v1 @-1 + element: <testLibrary>::@enum::A::@getter::v1 + staticType: A + rightBracket: ] @0 + staticType: List<A> + inducedGetter: #F7 + constructors + #F8 isConst isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:55) (offset:61) + element: <testLibrary>::@enum::A::@constructor::new + typeName: A + typeNameOffset: 61 + formalParameters + #F9 requiredPositional isOriginDeclaration value (nameOffset:67) (firstTokenOffset:63) (offset:67) + element: <testLibrary>::@enum::A::@constructor::new::@formalParameter::value + getters + #F4 isComplete isOriginVariable isStatic v1 (nameOffset:<null>) (firstTokenOffset:<null>) (offset:43) + element: <testLibrary>::@enum::A::@getter::v1 + inducingVariable: #F3 + nextFragment: #F10 + #F7 isComplete isOriginVariable isStatic values (nameOffset:<null>) (firstTokenOffset:<null>) (offset:37) + element: <testLibrary>::@enum::A::@getter::values + inducingVariable: #F6 + #F2 isAugmentation enum A (nameOffset:91) (firstTokenOffset:78) (offset:91) + element: <testLibrary>::@enum::A + previousFragment: #F1 + fields + #F5 hasImplicitType hasInitializer isAugmentation isConst isEnumConstant isOriginDeclaration isStatic v1 (nameOffset:105) (firstTokenOffset:97) (offset:105) + element: <testLibrary>::@enum::A::@field::v1 + initializer: expression_2 + ConstructorInvocation + constructorReference: ConstructorReference2 + typeReference: ConstructorTypeReference + name: A @-1 + element: <testLibrary>::@enum::A + type: A + element: <testLibrary>::@enum::A::@constructor::new + argumentList: ArgumentList + leftParenthesis: ( @107 + arguments2 + UnqualifiedNameExpression + name: one @108 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::one + invokeType: int Function() + type: int + staticType: int + arguments(v1) + SimpleIdentifier + token: one @108 + element: <testLibrary>::@getter::one + staticType: int + rightParenthesis: ) @111 + staticType: A + inducedGetter: #F10 + previousFragment: #F3 + getters + #F10 isAugmentation isComplete isOriginVariable isStatic v1 (nameOffset:<null>) (firstTokenOffset:<null>) (offset:105) + element: <testLibrary>::@enum::A::@getter::v1 + inducingVariable: #F5 + previousFragment: #F4 + topLevelVariables + #F11 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic zero (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::zero + initializer: expression_3 + IntegerLiteral + literal: 0 @13 + staticType: int + inducedGetter: #F12 + #F13 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic one (nameOffset:22) (firstTokenOffset:22) (offset:22) + element: <testLibrary>::@topLevelVariable::one + initializer: expression_4 + IntegerLiteral + literal: 1 @28 + staticType: int + inducedGetter: #F14 + getters + #F12 isComplete isOriginVariable isStatic zero (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::zero + inducingVariable: #F11 + #F14 isComplete isOriginVariable isStatic one (nameOffset:<null>) (firstTokenOffset:<null>) (offset:22) + element: <testLibrary>::@getter::one + inducingVariable: #F13 + enums + isSimplyBounded enum A + reference: <testLibrary>::@enum::A + firstFragment: #F1 + supertype: Enum + fields + hasImplicitType hasInitializer isConst isEnumConstant isOriginDeclaration isStatic isTypeInferredFromInitializer v1 + reference: <testLibrary>::@enum::A::@field::v1 + firstFragment: #F3 + type: A + constantInitializer + fragment: #F5 + expression: expression_2 + getter: <testLibrary>::@enum::A::@getter::v1 + isConst isOriginEnumValues isStatic values + reference: <testLibrary>::@enum::A::@field::values + firstFragment: #F6 + type: List<A> + constantInitializer + fragment: #F6 + expression: expression_1 + getter: <testLibrary>::@enum::A::@getter::values + constructors + isConst isOriginDeclaration new + reference: <testLibrary>::@enum::A::@constructor::new + firstFragment: #F8 + formalParameters + #E0 requiredPositional value + firstFragment: #F9 + type: int + superConstructor: dart:core::@class::Enum::@constructor::new + getters + isOriginVariable isStatic v1 + reference: <testLibrary>::@enum::A::@getter::v1 + firstFragment: #F4 + returnType: A + variable: <testLibrary>::@enum::A::@field::v1 + isOriginVariable isStatic values + reference: <testLibrary>::@enum::A::@getter::values + firstFragment: #F7 + returnType: List<A> + variable: <testLibrary>::@enum::A::@field::values + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer zero + reference: <testLibrary>::@topLevelVariable::zero + firstFragment: #F11 + type: int + constantInitializer + fragment: #F11 + expression: expression_3 + getter: <testLibrary>::@getter::zero + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer one + reference: <testLibrary>::@topLevelVariable::one + firstFragment: #F13 + type: int + constantInitializer + fragment: #F13 + expression: expression_4 + getter: <testLibrary>::@getter::one + getters + isOriginVariable isStatic zero + reference: <testLibrary>::@getter::zero + firstFragment: #F12 + returnType: int + variable: <testLibrary>::@topLevelVariable::zero + isOriginVariable isStatic one + reference: <testLibrary>::@getter::one + firstFragment: #F14 + returnType: int + variable: <testLibrary>::@topLevelVariable::one +'''); + } + test_constant_augmentation_introductoryHasConstants_augmentationHasConstants() async { var library = await buildLibrary(r''' enum A {
diff --git a/pkg/analyzer/test/src/summary/elements/metadata_test.dart b/pkg/analyzer/test/src/summary/elements/metadata_test.dart index 2c36fc5..393fcb9 100644 --- a/pkg/analyzer/test/src/summary/elements/metadata_test.dart +++ b/pkg/analyzer/test/src/summary/elements/metadata_test.dart
@@ -6,6 +6,7 @@ import 'package:test_reflective_loader/test_reflective_loader.dart'; import '../../dart/resolution/node_text_expectations.dart'; +import '../element_text.dart'; import '../elements_base.dart'; main() { @@ -505,6 +506,163 @@ '''); } + test_metadata_class_field_declaringFormalParameter_first() async { + var library = await buildLibrary(r''' +const a = 0; + +class A(@a final int foo); +'''); + // Check metadata without asking any other properties. + var foo = library.getClass('A')!.getField('foo')!; + configuration.withCombinedFragmentData(foo, CombinedFragmentData.metadata); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@field::foo + combined + metadata + annotation_0 + Annotation + atSign: @ @22 + expression: UnqualifiedNameExpression + name: a @23 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @23 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + fragments + #F0 +library + reference: <testLibrary> + fragments + #F1 <testLibraryFragment> + element: <testLibrary> + classes + #F2 class A (nameOffset:20) (firstTokenOffset:14) (offset:20) + element: <testLibrary>::@class::A + fields + #F0 isFinal isOriginDeclaringFormalParameter foo (nameOffset:<null>) (firstTokenOffset:<null>) (offset:20) + element: <testLibrary>::@class::A::@field::foo + inducedGetter: #F3 + constructors + #F4 isComplete isOriginDeclaration isPrimary new (nameOffset:<null>) (firstTokenOffset:20) (offset:20) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 20 + primaryHeaderCodeRange: 21 + 18 + formalParameters + #F5 requiredPositional isDeclaring isFinal isOriginDeclaration this.foo (nameOffset:35) (firstTokenOffset:22) (offset:35) + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::foo + metadata + Annotation + atSign: @ @22 + expression: UnqualifiedNameExpression + name: a @23 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @23 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + getters + #F3 isComplete isOriginVariable foo (nameOffset:<null>) (firstTokenOffset:<null>) (offset:20) + element: <testLibrary>::@class::A::@getter::foo + inducingVariable: #F0 + topLevelVariables + #F6 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic a (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::a + initializer: expression_0 + IntegerLiteral + literal: 0 @10 + staticType: int + inducedGetter: #F7 + getters + #F7 isComplete isOriginVariable isStatic a (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::a + inducingVariable: #F6 + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A + firstFragment: #F2 + fields + isFinal isOriginDeclaringFormalParameter foo + reference: <testLibrary>::@class::A::@field::foo + firstFragment: #F0 + metadata + Annotation + atSign: @ @22 + expression: UnqualifiedNameExpression + name: a @23 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @23 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + type: int + getter: <testLibrary>::@class::A::@getter::foo + declaringFormalParameter: <testLibrary>::@class::A::@constructor::new::@formalParameter::foo + constructors + isOriginDeclaration isPrimary new + reference: <testLibrary>::@class::A::@constructor::new + firstFragment: #F4 + formalParameters + #E0 requiredPositional isDeclaring isFinal this.foo + firstFragment: #F5 + type: int + metadata + Annotation + atSign: @ @22 + expression: UnqualifiedNameExpression + name: a @23 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @23 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + field: <testLibrary>::@class::A::@field::foo + getters + isOriginVariable foo + reference: <testLibrary>::@class::A::@getter::foo + firstFragment: #F3 + returnType: int + variable: <testLibrary>::@class::A::@field::foo + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer a + reference: <testLibrary>::@topLevelVariable::a + firstFragment: #F6 + type: int + constantInitializer + fragment: #F6 + expression: expression_0 + getter: <testLibrary>::@getter::a + getters + isOriginVariable isStatic a + reference: <testLibrary>::@getter::a + firstFragment: #F7 + returnType: int + variable: <testLibrary>::@topLevelVariable::a +'''); + } + test_metadata_class_field_first() async { var library = await buildLibrary(r''' const a = 0; @@ -7404,6 +7562,1950 @@ '''); } + test_metadata_simpleFormalParameter_augmentation_constructor_inAugmentation_first() async { + var library = await buildLibrary(r''' +const a = 0; + +class A { + A(int x); +} + +augment class A { + augment A(@a int x); +} +'''); + // Check metadata without asking any other properties. + var x = library.getClass('A')!.unnamedConstructor!.formalParameters.single; + configuration.withCombinedFragmentData(x, CombinedFragmentData.metadata); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + combined + metadata + annotation_0 + Annotation + atSign: @ @69 + expression: UnqualifiedNameExpression + name: a @70 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @70 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + fragments + #F0 + #F1 + metadata + annotation_0 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + classes + #F3 class A (nameOffset:20) (firstTokenOffset:14) (offset:20) + element: <testLibrary>::@class::A + nextFragment: #F4 + constructors + #F5 isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:26) (offset:26) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 26 + formalParameters + #F0 requiredPositional isOriginDeclaration x (nameOffset:32) (firstTokenOffset:28) (offset:32) + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + nextFragment: #F1 + nextFragment: #F6 + #F4 isAugmentation class A (nameOffset:53) (firstTokenOffset:39) (offset:53) + element: <testLibrary>::@class::A + previousFragment: #F3 + constructors + #F6 isAugmentation isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:59) (offset:67) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 67 + formalParameters + #F1 requiredPositional isOriginDeclaration x (nameOffset:76) (firstTokenOffset:69) (offset:76) + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + metadata + Annotation + atSign: @ @69 + expression: UnqualifiedNameExpression + name: a @70 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @70 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + previousFragment: #F0 + previousFragment: #F5 + topLevelVariables + #F7 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic a (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::a + initializer: expression_0 + IntegerLiteral + literal: 0 @10 + staticType: int + inducedGetter: #F8 + getters + #F8 isComplete isOriginVariable isStatic a (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::a + inducingVariable: #F7 + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A + firstFragment: #F3 + constructors + isOriginDeclaration new + reference: <testLibrary>::@class::A::@constructor::new + firstFragment: #F5 + formalParameters + #E0 requiredPositional x + firstFragment: #F0 + type: int + metadata + Annotation + atSign: @ @69 + expression: UnqualifiedNameExpression + name: a @70 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @70 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer a + reference: <testLibrary>::@topLevelVariable::a + firstFragment: #F7 + type: int + constantInitializer + fragment: #F7 + expression: expression_0 + getter: <testLibrary>::@getter::a + getters + isOriginVariable isStatic a + reference: <testLibrary>::@getter::a + firstFragment: #F8 + returnType: int + variable: <testLibrary>::@topLevelVariable::a +'''); + } + + test_metadata_simpleFormalParameter_augmentation_constructor_inBoth_first() async { + var library = await buildLibrary(r''' +const a = 0; +const b = 0; + +class A { + A(@a int x); +} + +augment class A { + augment A(@b int x); +} +'''); + // Check metadata without asking any other properties. + var x = library.getClass('A')!.unnamedConstructor!.formalParameters.single; + configuration.withCombinedFragmentData(x, CombinedFragmentData.metadata); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + combined + metadata + annotation_0 + Annotation + atSign: @ @41 + expression: UnqualifiedNameExpression + name: a @42 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @42 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + annotation_1 + Annotation + atSign: @ @85 + expression: UnqualifiedNameExpression + name: b @86 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::b + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: b @86 + element: <testLibrary>::@getter::b + staticType: null + element: <testLibrary>::@getter::b + fragments + #F0 + metadata + annotation_0 + #F1 + metadata + annotation_1 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + classes + #F3 class A (nameOffset:33) (firstTokenOffset:27) (offset:33) + element: <testLibrary>::@class::A + nextFragment: #F4 + constructors + #F5 isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:39) (offset:39) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 39 + formalParameters + #F0 requiredPositional isOriginDeclaration x (nameOffset:48) (firstTokenOffset:41) (offset:48) + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + metadata + Annotation + atSign: @ @41 + expression: UnqualifiedNameExpression + name: a @42 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @42 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + nextFragment: #F1 + nextFragment: #F6 + #F4 isAugmentation class A (nameOffset:69) (firstTokenOffset:55) (offset:69) + element: <testLibrary>::@class::A + previousFragment: #F3 + constructors + #F6 isAugmentation isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:75) (offset:83) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 83 + formalParameters + #F1 requiredPositional isOriginDeclaration x (nameOffset:92) (firstTokenOffset:85) (offset:92) + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + metadata + Annotation + atSign: @ @85 + expression: UnqualifiedNameExpression + name: b @86 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::b + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: b @86 + element: <testLibrary>::@getter::b + staticType: null + element: <testLibrary>::@getter::b + previousFragment: #F0 + previousFragment: #F5 + topLevelVariables + #F7 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic a (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::a + initializer: expression_0 + IntegerLiteral + literal: 0 @10 + staticType: int + inducedGetter: #F8 + #F9 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic b (nameOffset:19) (firstTokenOffset:19) (offset:19) + element: <testLibrary>::@topLevelVariable::b + initializer: expression_1 + IntegerLiteral + literal: 0 @23 + staticType: int + inducedGetter: #F10 + getters + #F8 isComplete isOriginVariable isStatic a (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::a + inducingVariable: #F7 + #F10 isComplete isOriginVariable isStatic b (nameOffset:<null>) (firstTokenOffset:<null>) (offset:19) + element: <testLibrary>::@getter::b + inducingVariable: #F9 + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A + firstFragment: #F3 + constructors + isOriginDeclaration new + reference: <testLibrary>::@class::A::@constructor::new + firstFragment: #F5 + formalParameters + #E0 requiredPositional x + firstFragment: #F0 + type: int + metadata + Annotation + atSign: @ @41 + expression: UnqualifiedNameExpression + name: a @42 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @42 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + Annotation + atSign: @ @85 + expression: UnqualifiedNameExpression + name: b @86 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::b + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: b @86 + element: <testLibrary>::@getter::b + staticType: null + element: <testLibrary>::@getter::b + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer a + reference: <testLibrary>::@topLevelVariable::a + firstFragment: #F7 + type: int + constantInitializer + fragment: #F7 + expression: expression_0 + getter: <testLibrary>::@getter::a + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer b + reference: <testLibrary>::@topLevelVariable::b + firstFragment: #F9 + type: int + constantInitializer + fragment: #F9 + expression: expression_1 + getter: <testLibrary>::@getter::b + getters + isOriginVariable isStatic a + reference: <testLibrary>::@getter::a + firstFragment: #F8 + returnType: int + variable: <testLibrary>::@topLevelVariable::a + isOriginVariable isStatic b + reference: <testLibrary>::@getter::b + firstFragment: #F10 + returnType: int + variable: <testLibrary>::@topLevelVariable::b +'''); + } + + test_metadata_simpleFormalParameter_augmentation_constructor_inIntroductory_first() async { + var library = await buildLibrary(r''' +const a = 0; + +class A { + A(@a int x); +} + +augment class A { + augment A(int x); +} +'''); + // Check metadata without asking any other properties, reaching + // the element via the augmentation, so the introductory fragment is not + // read. + var constructor = library.getClass('A')!.unnamedConstructor!; + var x = constructor.fragments.last.formalParameters.single.element; + configuration.withCombinedFragmentData(x, CombinedFragmentData.metadata); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + combined + metadata + annotation_0 + Annotation + atSign: @ @28 + expression: UnqualifiedNameExpression + name: a @29 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @29 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + fragments + #F0 + metadata + annotation_0 + #F1 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + classes + #F3 class A (nameOffset:20) (firstTokenOffset:14) (offset:20) + element: <testLibrary>::@class::A + nextFragment: #F4 + constructors + #F5 isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:26) (offset:26) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 26 + formalParameters + #F0 requiredPositional isOriginDeclaration x (nameOffset:35) (firstTokenOffset:28) (offset:35) + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + metadata + Annotation + atSign: @ @28 + expression: UnqualifiedNameExpression + name: a @29 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @29 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + nextFragment: #F1 + nextFragment: #F6 + #F4 isAugmentation class A (nameOffset:56) (firstTokenOffset:42) (offset:56) + element: <testLibrary>::@class::A + previousFragment: #F3 + constructors + #F6 isAugmentation isOriginDeclaration new (nameOffset:<null>) (firstTokenOffset:62) (offset:70) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + typeNameOffset: 70 + formalParameters + #F1 requiredPositional isOriginDeclaration x (nameOffset:76) (firstTokenOffset:72) (offset:76) + element: <testLibrary>::@class::A::@constructor::new::@formalParameter::x + previousFragment: #F0 + previousFragment: #F5 + topLevelVariables + #F7 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic a (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::a + initializer: expression_0 + IntegerLiteral + literal: 0 @10 + staticType: int + inducedGetter: #F8 + getters + #F8 isComplete isOriginVariable isStatic a (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::a + inducingVariable: #F7 + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A + firstFragment: #F3 + constructors + isOriginDeclaration new + reference: <testLibrary>::@class::A::@constructor::new + firstFragment: #F5 + formalParameters + #E0 requiredPositional x + firstFragment: #F0 + type: int + metadata + Annotation + atSign: @ @28 + expression: UnqualifiedNameExpression + name: a @29 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @29 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer a + reference: <testLibrary>::@topLevelVariable::a + firstFragment: #F7 + type: int + constantInitializer + fragment: #F7 + expression: expression_0 + getter: <testLibrary>::@getter::a + getters + isOriginVariable isStatic a + reference: <testLibrary>::@getter::a + firstFragment: #F8 + returnType: int + variable: <testLibrary>::@topLevelVariable::a +'''); + } + + test_metadata_simpleFormalParameter_augmentation_method_inAugmentation_first() async { + var library = await buildLibrary(r''' +const a = 0; + +class A { + void foo(int x); +} + +augment class A { + augment void foo(@a int x) {} +} +'''); + // Check metadata without asking any other properties. + var x = library.getClass('A')!.getMethod('foo')!.formalParameters.single; + configuration.withCombinedFragmentData(x, CombinedFragmentData.metadata); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + combined + metadata + annotation_0 + Annotation + atSign: @ @83 + expression: UnqualifiedNameExpression + name: a @84 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @84 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + fragments + #F0 + #F1 + metadata + annotation_0 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + classes + #F3 class A (nameOffset:20) (firstTokenOffset:14) (offset:20) + element: <testLibrary>::@class::A + nextFragment: #F4 + constructors + #F5 isOriginImplicitDefault new (nameOffset:<null>) (firstTokenOffset:<null>) (offset:20) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + methods + #F6 isAbstract isOriginDeclaration foo (nameOffset:31) (firstTokenOffset:26) (offset:31) + element: <testLibrary>::@class::A::@method::foo + nextFragment: #F7 + formalParameters + #F0 requiredPositional isOriginDeclaration x (nameOffset:39) (firstTokenOffset:35) (offset:39) + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + nextFragment: #F1 + #F4 isAugmentation class A (nameOffset:60) (firstTokenOffset:46) (offset:60) + element: <testLibrary>::@class::A + previousFragment: #F3 + methods + #F7 isAugmentation isComplete isOriginDeclaration foo (nameOffset:79) (firstTokenOffset:66) (offset:79) + element: <testLibrary>::@class::A::@method::foo + previousFragment: #F6 + formalParameters + #F1 requiredPositional isOriginDeclaration x (nameOffset:90) (firstTokenOffset:83) (offset:90) + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + metadata + Annotation + atSign: @ @83 + expression: UnqualifiedNameExpression + name: a @84 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @84 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + previousFragment: #F0 + topLevelVariables + #F8 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic a (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::a + initializer: expression_0 + IntegerLiteral + literal: 0 @10 + staticType: int + inducedGetter: #F9 + getters + #F9 isComplete isOriginVariable isStatic a (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::a + inducingVariable: #F8 + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A + firstFragment: #F3 + constructors + isOriginImplicitDefault new + reference: <testLibrary>::@class::A::@constructor::new + firstFragment: #F5 + methods + isOriginDeclaration foo + reference: <testLibrary>::@class::A::@method::foo + firstFragment: #F6 + formalParameters + #E0 requiredPositional x + firstFragment: #F0 + type: int + metadata + Annotation + atSign: @ @83 + expression: UnqualifiedNameExpression + name: a @84 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @84 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + returnType: void + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer a + reference: <testLibrary>::@topLevelVariable::a + firstFragment: #F8 + type: int + constantInitializer + fragment: #F8 + expression: expression_0 + getter: <testLibrary>::@getter::a + getters + isOriginVariable isStatic a + reference: <testLibrary>::@getter::a + firstFragment: #F9 + returnType: int + variable: <testLibrary>::@topLevelVariable::a +'''); + } + + test_metadata_simpleFormalParameter_augmentation_method_inBoth_first() async { + var library = await buildLibrary(r''' +const a = 0; +const b = 0; + +class A { + void foo(@a int x); +} + +augment class A { + augment void foo(@b int x) {} +} +'''); + // Check metadata without asking any other properties. + var x = library.getClass('A')!.getMethod('foo')!.formalParameters.single; + configuration.withCombinedFragmentData(x, CombinedFragmentData.metadata); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + combined + metadata + annotation_0 + Annotation + atSign: @ @48 + expression: UnqualifiedNameExpression + name: a @49 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @49 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + annotation_1 + Annotation + atSign: @ @99 + expression: UnqualifiedNameExpression + name: b @100 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::b + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: b @100 + element: <testLibrary>::@getter::b + staticType: null + element: <testLibrary>::@getter::b + fragments + #F0 + metadata + annotation_0 + #F1 + metadata + annotation_1 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + classes + #F3 class A (nameOffset:33) (firstTokenOffset:27) (offset:33) + element: <testLibrary>::@class::A + nextFragment: #F4 + constructors + #F5 isOriginImplicitDefault new (nameOffset:<null>) (firstTokenOffset:<null>) (offset:33) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + methods + #F6 isAbstract isOriginDeclaration foo (nameOffset:44) (firstTokenOffset:39) (offset:44) + element: <testLibrary>::@class::A::@method::foo + nextFragment: #F7 + formalParameters + #F0 requiredPositional isOriginDeclaration x (nameOffset:55) (firstTokenOffset:48) (offset:55) + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + metadata + Annotation + atSign: @ @48 + expression: UnqualifiedNameExpression + name: a @49 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @49 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + nextFragment: #F1 + #F4 isAugmentation class A (nameOffset:76) (firstTokenOffset:62) (offset:76) + element: <testLibrary>::@class::A + previousFragment: #F3 + methods + #F7 isAugmentation isComplete isOriginDeclaration foo (nameOffset:95) (firstTokenOffset:82) (offset:95) + element: <testLibrary>::@class::A::@method::foo + previousFragment: #F6 + formalParameters + #F1 requiredPositional isOriginDeclaration x (nameOffset:106) (firstTokenOffset:99) (offset:106) + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + metadata + Annotation + atSign: @ @99 + expression: UnqualifiedNameExpression + name: b @100 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::b + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: b @100 + element: <testLibrary>::@getter::b + staticType: null + element: <testLibrary>::@getter::b + previousFragment: #F0 + topLevelVariables + #F8 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic a (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::a + initializer: expression_0 + IntegerLiteral + literal: 0 @10 + staticType: int + inducedGetter: #F9 + #F10 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic b (nameOffset:19) (firstTokenOffset:19) (offset:19) + element: <testLibrary>::@topLevelVariable::b + initializer: expression_1 + IntegerLiteral + literal: 0 @23 + staticType: int + inducedGetter: #F11 + getters + #F9 isComplete isOriginVariable isStatic a (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::a + inducingVariable: #F8 + #F11 isComplete isOriginVariable isStatic b (nameOffset:<null>) (firstTokenOffset:<null>) (offset:19) + element: <testLibrary>::@getter::b + inducingVariable: #F10 + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A + firstFragment: #F3 + constructors + isOriginImplicitDefault new + reference: <testLibrary>::@class::A::@constructor::new + firstFragment: #F5 + methods + isOriginDeclaration foo + reference: <testLibrary>::@class::A::@method::foo + firstFragment: #F6 + formalParameters + #E0 requiredPositional x + firstFragment: #F0 + type: int + metadata + Annotation + atSign: @ @48 + expression: UnqualifiedNameExpression + name: a @49 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @49 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + Annotation + atSign: @ @99 + expression: UnqualifiedNameExpression + name: b @100 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::b + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: b @100 + element: <testLibrary>::@getter::b + staticType: null + element: <testLibrary>::@getter::b + returnType: void + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer a + reference: <testLibrary>::@topLevelVariable::a + firstFragment: #F8 + type: int + constantInitializer + fragment: #F8 + expression: expression_0 + getter: <testLibrary>::@getter::a + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer b + reference: <testLibrary>::@topLevelVariable::b + firstFragment: #F10 + type: int + constantInitializer + fragment: #F10 + expression: expression_1 + getter: <testLibrary>::@getter::b + getters + isOriginVariable isStatic a + reference: <testLibrary>::@getter::a + firstFragment: #F9 + returnType: int + variable: <testLibrary>::@topLevelVariable::a + isOriginVariable isStatic b + reference: <testLibrary>::@getter::b + firstFragment: #F11 + returnType: int + variable: <testLibrary>::@topLevelVariable::b +'''); + } + + test_metadata_simpleFormalParameter_augmentation_method_inIntroductory_first() async { + var library = await buildLibrary(r''' +const a = 0; + +class A { + void foo(@a int x); +} + +augment class A { + augment void foo(int x) {} +} +'''); + // Check metadata without asking any other properties, reaching + // the element via the augmentation, so the introductory fragment is not + // read. + var foo = library.getClass('A')!.getMethod('foo')!; + var x = foo.fragments.last.formalParameters.single.element; + configuration.withCombinedFragmentData(x, CombinedFragmentData.metadata); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + combined + metadata + annotation_0 + Annotation + atSign: @ @35 + expression: UnqualifiedNameExpression + name: a @36 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @36 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + fragments + #F0 + metadata + annotation_0 + #F1 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + classes + #F3 class A (nameOffset:20) (firstTokenOffset:14) (offset:20) + element: <testLibrary>::@class::A + nextFragment: #F4 + constructors + #F5 isOriginImplicitDefault new (nameOffset:<null>) (firstTokenOffset:<null>) (offset:20) + element: <testLibrary>::@class::A::@constructor::new + typeName: A + methods + #F6 isAbstract isOriginDeclaration foo (nameOffset:31) (firstTokenOffset:26) (offset:31) + element: <testLibrary>::@class::A::@method::foo + nextFragment: #F7 + formalParameters + #F0 requiredPositional isOriginDeclaration x (nameOffset:42) (firstTokenOffset:35) (offset:42) + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + metadata + Annotation + atSign: @ @35 + expression: UnqualifiedNameExpression + name: a @36 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @36 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + nextFragment: #F1 + #F4 isAugmentation class A (nameOffset:63) (firstTokenOffset:49) (offset:63) + element: <testLibrary>::@class::A + previousFragment: #F3 + methods + #F7 isAugmentation isComplete isOriginDeclaration foo (nameOffset:82) (firstTokenOffset:69) (offset:82) + element: <testLibrary>::@class::A::@method::foo + previousFragment: #F6 + formalParameters + #F1 requiredPositional isOriginDeclaration x (nameOffset:90) (firstTokenOffset:86) (offset:90) + element: <testLibrary>::@class::A::@method::foo::@formalParameter::x + previousFragment: #F0 + topLevelVariables + #F8 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic a (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::a + initializer: expression_0 + IntegerLiteral + literal: 0 @10 + staticType: int + inducedGetter: #F9 + getters + #F9 isComplete isOriginVariable isStatic a (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::a + inducingVariable: #F8 + classes + isSimplyBounded class A + reference: <testLibrary>::@class::A + firstFragment: #F3 + constructors + isOriginImplicitDefault new + reference: <testLibrary>::@class::A::@constructor::new + firstFragment: #F5 + methods + isOriginDeclaration foo + reference: <testLibrary>::@class::A::@method::foo + firstFragment: #F6 + formalParameters + #E0 requiredPositional x + firstFragment: #F0 + type: int + metadata + Annotation + atSign: @ @35 + expression: UnqualifiedNameExpression + name: a @36 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @36 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + returnType: void + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer a + reference: <testLibrary>::@topLevelVariable::a + firstFragment: #F8 + type: int + constantInitializer + fragment: #F8 + expression: expression_0 + getter: <testLibrary>::@getter::a + getters + isOriginVariable isStatic a + reference: <testLibrary>::@getter::a + firstFragment: #F9 + returnType: int + variable: <testLibrary>::@topLevelVariable::a +'''); + } + + test_metadata_simpleFormalParameter_augmentation_setter_inAugmentation_first() async { + var library = await buildLibrary(r''' +const a = 0; + +set foo(int x); + +augment set foo(@a int x) {} +'''); + // Check metadata without asking any other properties. + var x = library.getSetter('foo')!.formalParameters.single; + configuration.withCombinedFragmentData(x, CombinedFragmentData.metadata); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@setter::foo::@formalParameter::x + combined + metadata + annotation_0 + Annotation + atSign: @ @47 + expression: UnqualifiedNameExpression + name: a @48 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @48 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + fragments + #F0 + #F1 + metadata + annotation_0 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + topLevelVariables + #F3 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic a (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::a + initializer: expression_0 + IntegerLiteral + literal: 0 @10 + staticType: int + inducedGetter: #F4 + #F5 isOriginGetterSetter isStatic foo (nameOffset:<null>) (firstTokenOffset:<null>) (offset:18) + element: <testLibrary>::@topLevelVariable::foo + getters + #F4 isComplete isOriginVariable isStatic a (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::a + inducingVariable: #F3 + setters + #F6 hasImplicitReturnType isOriginDeclaration isStatic foo (nameOffset:18) (firstTokenOffset:14) (offset:18) + element: <testLibrary>::@setter::foo + formalParameters + #F0 requiredPositional isOriginDeclaration x (nameOffset:26) (firstTokenOffset:22) (offset:26) + element: <testLibrary>::@setter::foo::@formalParameter::x + nextFragment: #F1 + nextFragment: #F7 + #F7 hasImplicitReturnType isAugmentation isComplete isOriginDeclaration isStatic foo (nameOffset:43) (firstTokenOffset:31) (offset:43) + element: <testLibrary>::@setter::foo + formalParameters + #F1 requiredPositional isOriginDeclaration x (nameOffset:54) (firstTokenOffset:47) (offset:54) + element: <testLibrary>::@setter::foo::@formalParameter::x + metadata + Annotation + atSign: @ @47 + expression: UnqualifiedNameExpression + name: a @48 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @48 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + previousFragment: #F0 + previousFragment: #F6 + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer a + reference: <testLibrary>::@topLevelVariable::a + firstFragment: #F3 + type: int + constantInitializer + fragment: #F3 + expression: expression_0 + getter: <testLibrary>::@getter::a + isOriginGetterSetter isStatic foo + reference: <testLibrary>::@topLevelVariable::foo + firstFragment: #F5 + type: int + setter: <testLibrary>::@setter::foo + getters + isOriginVariable isStatic a + reference: <testLibrary>::@getter::a + firstFragment: #F4 + returnType: int + variable: <testLibrary>::@topLevelVariable::a + setters + hasImplicitReturnType isOriginDeclaration isStatic foo + reference: <testLibrary>::@setter::foo + firstFragment: #F6 + formalParameters + #E0 requiredPositional x + firstFragment: #F0 + type: int + metadata + Annotation + atSign: @ @47 + expression: UnqualifiedNameExpression + name: a @48 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @48 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + returnType: void + variable: <testLibrary>::@topLevelVariable::foo +'''); + } + + test_metadata_simpleFormalParameter_augmentation_setter_inBoth_first() async { + var library = await buildLibrary(r''' +const a = 0; +const b = 0; + +set foo(@a int x); + +augment set foo(@b int x) {} +'''); + // Check metadata without asking any other properties. + var x = library.getSetter('foo')!.formalParameters.single; + configuration.withCombinedFragmentData(x, CombinedFragmentData.metadata); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@setter::foo::@formalParameter::x + combined + metadata + annotation_0 + Annotation + atSign: @ @35 + expression: UnqualifiedNameExpression + name: a @36 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @36 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + annotation_1 + Annotation + atSign: @ @63 + expression: UnqualifiedNameExpression + name: b @64 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::b + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: b @64 + element: <testLibrary>::@getter::b + staticType: null + element: <testLibrary>::@getter::b + fragments + #F0 + metadata + annotation_0 + #F1 + metadata + annotation_1 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + topLevelVariables + #F3 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic a (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::a + initializer: expression_0 + IntegerLiteral + literal: 0 @10 + staticType: int + inducedGetter: #F4 + #F5 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic b (nameOffset:19) (firstTokenOffset:19) (offset:19) + element: <testLibrary>::@topLevelVariable::b + initializer: expression_1 + IntegerLiteral + literal: 0 @23 + staticType: int + inducedGetter: #F6 + #F7 isOriginGetterSetter isStatic foo (nameOffset:<null>) (firstTokenOffset:<null>) (offset:31) + element: <testLibrary>::@topLevelVariable::foo + getters + #F4 isComplete isOriginVariable isStatic a (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::a + inducingVariable: #F3 + #F6 isComplete isOriginVariable isStatic b (nameOffset:<null>) (firstTokenOffset:<null>) (offset:19) + element: <testLibrary>::@getter::b + inducingVariable: #F5 + setters + #F8 hasImplicitReturnType isOriginDeclaration isStatic foo (nameOffset:31) (firstTokenOffset:27) (offset:31) + element: <testLibrary>::@setter::foo + formalParameters + #F0 requiredPositional isOriginDeclaration x (nameOffset:42) (firstTokenOffset:35) (offset:42) + element: <testLibrary>::@setter::foo::@formalParameter::x + metadata + Annotation + atSign: @ @35 + expression: UnqualifiedNameExpression + name: a @36 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @36 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + nextFragment: #F1 + nextFragment: #F9 + #F9 hasImplicitReturnType isAugmentation isComplete isOriginDeclaration isStatic foo (nameOffset:59) (firstTokenOffset:47) (offset:59) + element: <testLibrary>::@setter::foo + formalParameters + #F1 requiredPositional isOriginDeclaration x (nameOffset:70) (firstTokenOffset:63) (offset:70) + element: <testLibrary>::@setter::foo::@formalParameter::x + metadata + Annotation + atSign: @ @63 + expression: UnqualifiedNameExpression + name: b @64 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::b + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: b @64 + element: <testLibrary>::@getter::b + staticType: null + element: <testLibrary>::@getter::b + previousFragment: #F0 + previousFragment: #F8 + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer a + reference: <testLibrary>::@topLevelVariable::a + firstFragment: #F3 + type: int + constantInitializer + fragment: #F3 + expression: expression_0 + getter: <testLibrary>::@getter::a + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer b + reference: <testLibrary>::@topLevelVariable::b + firstFragment: #F5 + type: int + constantInitializer + fragment: #F5 + expression: expression_1 + getter: <testLibrary>::@getter::b + isOriginGetterSetter isStatic foo + reference: <testLibrary>::@topLevelVariable::foo + firstFragment: #F7 + type: int + setter: <testLibrary>::@setter::foo + getters + isOriginVariable isStatic a + reference: <testLibrary>::@getter::a + firstFragment: #F4 + returnType: int + variable: <testLibrary>::@topLevelVariable::a + isOriginVariable isStatic b + reference: <testLibrary>::@getter::b + firstFragment: #F6 + returnType: int + variable: <testLibrary>::@topLevelVariable::b + setters + hasImplicitReturnType isOriginDeclaration isStatic foo + reference: <testLibrary>::@setter::foo + firstFragment: #F8 + formalParameters + #E0 requiredPositional x + firstFragment: #F0 + type: int + metadata + Annotation + atSign: @ @35 + expression: UnqualifiedNameExpression + name: a @36 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @36 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + Annotation + atSign: @ @63 + expression: UnqualifiedNameExpression + name: b @64 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::b + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: b @64 + element: <testLibrary>::@getter::b + staticType: null + element: <testLibrary>::@getter::b + returnType: void + variable: <testLibrary>::@topLevelVariable::foo +'''); + } + + test_metadata_simpleFormalParameter_augmentation_setter_inIntroductory_first() async { + var library = await buildLibrary(r''' +const a = 0; + +set foo(@a int x); + +augment set foo(int x) {} +'''); + // Check metadata without asking any other properties, reaching + // the element via the augmentation, so the introductory fragment is not + // read. + var foo = library.getSetter('foo')!; + var x = foo.fragments.last.formalParameters.single.element; + configuration.withCombinedFragmentData(x, CombinedFragmentData.metadata); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@setter::foo::@formalParameter::x + combined + metadata + annotation_0 + Annotation + atSign: @ @22 + expression: UnqualifiedNameExpression + name: a @23 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @23 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + fragments + #F0 + metadata + annotation_0 + #F1 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + topLevelVariables + #F3 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic a (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::a + initializer: expression_0 + IntegerLiteral + literal: 0 @10 + staticType: int + inducedGetter: #F4 + #F5 isOriginGetterSetter isStatic foo (nameOffset:<null>) (firstTokenOffset:<null>) (offset:18) + element: <testLibrary>::@topLevelVariable::foo + getters + #F4 isComplete isOriginVariable isStatic a (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::a + inducingVariable: #F3 + setters + #F6 hasImplicitReturnType isOriginDeclaration isStatic foo (nameOffset:18) (firstTokenOffset:14) (offset:18) + element: <testLibrary>::@setter::foo + formalParameters + #F0 requiredPositional isOriginDeclaration x (nameOffset:29) (firstTokenOffset:22) (offset:29) + element: <testLibrary>::@setter::foo::@formalParameter::x + metadata + Annotation + atSign: @ @22 + expression: UnqualifiedNameExpression + name: a @23 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @23 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + nextFragment: #F1 + nextFragment: #F7 + #F7 hasImplicitReturnType isAugmentation isComplete isOriginDeclaration isStatic foo (nameOffset:46) (firstTokenOffset:34) (offset:46) + element: <testLibrary>::@setter::foo + formalParameters + #F1 requiredPositional isOriginDeclaration x (nameOffset:54) (firstTokenOffset:50) (offset:54) + element: <testLibrary>::@setter::foo::@formalParameter::x + previousFragment: #F0 + previousFragment: #F6 + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer a + reference: <testLibrary>::@topLevelVariable::a + firstFragment: #F3 + type: int + constantInitializer + fragment: #F3 + expression: expression_0 + getter: <testLibrary>::@getter::a + isOriginGetterSetter isStatic foo + reference: <testLibrary>::@topLevelVariable::foo + firstFragment: #F5 + type: int + setter: <testLibrary>::@setter::foo + getters + isOriginVariable isStatic a + reference: <testLibrary>::@getter::a + firstFragment: #F4 + returnType: int + variable: <testLibrary>::@topLevelVariable::a + setters + hasImplicitReturnType isOriginDeclaration isStatic foo + reference: <testLibrary>::@setter::foo + firstFragment: #F6 + formalParameters + #E0 requiredPositional x + firstFragment: #F0 + type: int + metadata + Annotation + atSign: @ @22 + expression: UnqualifiedNameExpression + name: a @23 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @23 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + returnType: void + variable: <testLibrary>::@topLevelVariable::foo +'''); + } + + test_metadata_simpleFormalParameter_augmentation_topLevelFunction_inAugmentation_first() async { + var library = await buildLibrary(r''' +const a = null; + +void foo(int x); + +augment void foo(@a int x) {} +'''); + // Check metadata without asking any other properties. + var x = library.getTopLevelFunction('foo')!.formalParameters.single; + configuration.withCombinedFragmentData(x, CombinedFragmentData.metadata); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@function::foo::@formalParameter::x + combined + metadata + annotation_0 + Annotation + atSign: @ @52 + expression: UnqualifiedNameExpression + name: a @53 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: dynamic Function() + type: dynamic + staticType: dynamic + name: SimpleIdentifier + token: a @53 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + fragments + #F0 + #F1 + metadata + annotation_0 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + topLevelVariables + #F3 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic a (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::a + initializer: expression_0 + NullLiteral + literal: null @10 + staticType: Null + inducedGetter: #F4 + getters + #F4 isComplete isOriginVariable isStatic a (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::a + inducingVariable: #F3 + functions + #F5 isOriginDeclaration isStatic foo (nameOffset:22) (firstTokenOffset:17) (offset:22) + element: <testLibrary>::@function::foo + nextFragment: #F6 + formalParameters + #F0 requiredPositional isOriginDeclaration x (nameOffset:30) (firstTokenOffset:26) (offset:30) + element: <testLibrary>::@function::foo::@formalParameter::x + nextFragment: #F1 + #F6 isAugmentation isComplete isOriginDeclaration isStatic foo (nameOffset:48) (firstTokenOffset:35) (offset:48) + element: <testLibrary>::@function::foo + previousFragment: #F5 + formalParameters + #F1 requiredPositional isOriginDeclaration x (nameOffset:59) (firstTokenOffset:52) (offset:59) + element: <testLibrary>::@function::foo::@formalParameter::x + metadata + Annotation + atSign: @ @52 + expression: UnqualifiedNameExpression + name: a @53 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: dynamic Function() + type: dynamic + staticType: dynamic + name: SimpleIdentifier + token: a @53 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + previousFragment: #F0 + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer a + reference: <testLibrary>::@topLevelVariable::a + firstFragment: #F3 + type: dynamic + constantInitializer + fragment: #F3 + expression: expression_0 + getter: <testLibrary>::@getter::a + getters + isOriginVariable isStatic a + reference: <testLibrary>::@getter::a + firstFragment: #F4 + returnType: dynamic + variable: <testLibrary>::@topLevelVariable::a + functions + isOriginDeclaration isStatic foo + reference: <testLibrary>::@function::foo + firstFragment: #F5 + formalParameters + #E0 requiredPositional x + firstFragment: #F0 + type: int + metadata + Annotation + atSign: @ @52 + expression: UnqualifiedNameExpression + name: a @53 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: dynamic Function() + type: dynamic + staticType: dynamic + name: SimpleIdentifier + token: a @53 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + returnType: void +'''); + } + + test_metadata_simpleFormalParameter_augmentation_topLevelFunction_inBoth_first() async { + var library = await buildLibrary(r''' +const a = 0; +const b = 0; + +void foo(@a int x); + +augment void foo(@b int x) {} +'''); + // Check metadata without asking any other properties. + var x = library.getTopLevelFunction('foo')!.formalParameters.single; + configuration.withCombinedFragmentData(x, CombinedFragmentData.metadata); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@function::foo::@formalParameter::x + combined + metadata + annotation_0 + Annotation + atSign: @ @36 + expression: UnqualifiedNameExpression + name: a @37 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @37 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + annotation_1 + Annotation + atSign: @ @65 + expression: UnqualifiedNameExpression + name: b @66 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::b + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: b @66 + element: <testLibrary>::@getter::b + staticType: null + element: <testLibrary>::@getter::b + fragments + #F0 + metadata + annotation_0 + #F1 + metadata + annotation_1 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + topLevelVariables + #F3 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic a (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::a + initializer: expression_0 + IntegerLiteral + literal: 0 @10 + staticType: int + inducedGetter: #F4 + #F5 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic b (nameOffset:19) (firstTokenOffset:19) (offset:19) + element: <testLibrary>::@topLevelVariable::b + initializer: expression_1 + IntegerLiteral + literal: 0 @23 + staticType: int + inducedGetter: #F6 + getters + #F4 isComplete isOriginVariable isStatic a (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::a + inducingVariable: #F3 + #F6 isComplete isOriginVariable isStatic b (nameOffset:<null>) (firstTokenOffset:<null>) (offset:19) + element: <testLibrary>::@getter::b + inducingVariable: #F5 + functions + #F7 isOriginDeclaration isStatic foo (nameOffset:32) (firstTokenOffset:27) (offset:32) + element: <testLibrary>::@function::foo + nextFragment: #F8 + formalParameters + #F0 requiredPositional isOriginDeclaration x (nameOffset:43) (firstTokenOffset:36) (offset:43) + element: <testLibrary>::@function::foo::@formalParameter::x + metadata + Annotation + atSign: @ @36 + expression: UnqualifiedNameExpression + name: a @37 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @37 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + nextFragment: #F1 + #F8 isAugmentation isComplete isOriginDeclaration isStatic foo (nameOffset:61) (firstTokenOffset:48) (offset:61) + element: <testLibrary>::@function::foo + previousFragment: #F7 + formalParameters + #F1 requiredPositional isOriginDeclaration x (nameOffset:72) (firstTokenOffset:65) (offset:72) + element: <testLibrary>::@function::foo::@formalParameter::x + metadata + Annotation + atSign: @ @65 + expression: UnqualifiedNameExpression + name: b @66 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::b + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: b @66 + element: <testLibrary>::@getter::b + staticType: null + element: <testLibrary>::@getter::b + previousFragment: #F0 + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer a + reference: <testLibrary>::@topLevelVariable::a + firstFragment: #F3 + type: int + constantInitializer + fragment: #F3 + expression: expression_0 + getter: <testLibrary>::@getter::a + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer b + reference: <testLibrary>::@topLevelVariable::b + firstFragment: #F5 + type: int + constantInitializer + fragment: #F5 + expression: expression_1 + getter: <testLibrary>::@getter::b + getters + isOriginVariable isStatic a + reference: <testLibrary>::@getter::a + firstFragment: #F4 + returnType: int + variable: <testLibrary>::@topLevelVariable::a + isOriginVariable isStatic b + reference: <testLibrary>::@getter::b + firstFragment: #F6 + returnType: int + variable: <testLibrary>::@topLevelVariable::b + functions + isOriginDeclaration isStatic foo + reference: <testLibrary>::@function::foo + firstFragment: #F7 + formalParameters + #E0 requiredPositional x + firstFragment: #F0 + type: int + metadata + Annotation + atSign: @ @36 + expression: UnqualifiedNameExpression + name: a @37 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: a @37 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + Annotation + atSign: @ @65 + expression: UnqualifiedNameExpression + name: b @66 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::b + invokeType: int Function() + type: int + staticType: int + name: SimpleIdentifier + token: b @66 + element: <testLibrary>::@getter::b + staticType: null + element: <testLibrary>::@getter::b + returnType: void +'''); + } + + test_metadata_simpleFormalParameter_augmentation_topLevelFunction_inIntroductory_first() async { + var library = await buildLibrary(r''' +const a = null; + +void foo(@a int x); + +augment void foo(int x) {} +'''); + // Check metadata without asking any other properties, reaching the + // element via the augmentation, so the introductory fragment is not read. + var foo = library.getTopLevelFunction('foo')!; + var x = foo.fragments.last.formalParameters.single.element; + configuration.withCombinedFragmentData(x, CombinedFragmentData.metadata); + checkElementText(library, r''' +combinedFragmentData + element: <testLibrary>::@function::foo::@formalParameter::x + combined + metadata + annotation_0 + Annotation + atSign: @ @26 + expression: UnqualifiedNameExpression + name: a @27 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: dynamic Function() + type: dynamic + staticType: dynamic + name: SimpleIdentifier + token: a @27 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + fragments + #F0 + metadata + annotation_0 + #F1 +library + reference: <testLibrary> + fragments + #F2 <testLibraryFragment> + element: <testLibrary> + topLevelVariables + #F3 hasImplicitType hasInitializer isConst isOriginDeclaration isStatic a (nameOffset:6) (firstTokenOffset:6) (offset:6) + element: <testLibrary>::@topLevelVariable::a + initializer: expression_0 + NullLiteral + literal: null @10 + staticType: Null + inducedGetter: #F4 + getters + #F4 isComplete isOriginVariable isStatic a (nameOffset:<null>) (firstTokenOffset:<null>) (offset:6) + element: <testLibrary>::@getter::a + inducingVariable: #F3 + functions + #F5 isOriginDeclaration isStatic foo (nameOffset:22) (firstTokenOffset:17) (offset:22) + element: <testLibrary>::@function::foo + nextFragment: #F6 + formalParameters + #F0 requiredPositional isOriginDeclaration x (nameOffset:33) (firstTokenOffset:26) (offset:33) + element: <testLibrary>::@function::foo::@formalParameter::x + metadata + Annotation + atSign: @ @26 + expression: UnqualifiedNameExpression + name: a @27 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: dynamic Function() + type: dynamic + staticType: dynamic + name: SimpleIdentifier + token: a @27 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + nextFragment: #F1 + #F6 isAugmentation isComplete isOriginDeclaration isStatic foo (nameOffset:51) (firstTokenOffset:38) (offset:51) + element: <testLibrary>::@function::foo + previousFragment: #F5 + formalParameters + #F1 requiredPositional isOriginDeclaration x (nameOffset:59) (firstTokenOffset:55) (offset:59) + element: <testLibrary>::@function::foo::@formalParameter::x + previousFragment: #F0 + topLevelVariables + hasImplicitType hasInitializer isConst isOriginDeclaration isStatic isTypeInferredFromInitializer a + reference: <testLibrary>::@topLevelVariable::a + firstFragment: #F3 + type: dynamic + constantInitializer + fragment: #F3 + expression: expression_0 + getter: <testLibrary>::@getter::a + getters + isOriginVariable isStatic a + reference: <testLibrary>::@getter::a + firstFragment: #F4 + returnType: dynamic + variable: <testLibrary>::@topLevelVariable::a + functions + isOriginDeclaration isStatic foo + reference: <testLibrary>::@function::foo + firstFragment: #F5 + formalParameters + #E0 requiredPositional x + firstFragment: #F0 + type: int + metadata + Annotation + atSign: @ @26 + expression: UnqualifiedNameExpression + name: a @27 + resolution: GetterInvocationResolution + element: <testLibrary>::@getter::a + invokeType: dynamic Function() + type: dynamic + staticType: dynamic + name: SimpleIdentifier + token: a @27 + element: <testLibrary>::@getter::a + staticType: null + element: <testLibrary>::@getter::a + returnType: void +'''); + } + test_metadata_simpleFormalParameter_method() async { var library = await buildLibrary(r''' const a = null;
diff --git a/pkg/analyzer/test/src/utilities/hash/blake3_reference.dart b/pkg/analyzer/test/src/utilities/hash/blake3_reference.dart new file mode 100644 index 0000000..493963d --- /dev/null +++ b/pkg/analyzer/test/src/utilities/hash/blake3_reference.dart
@@ -0,0 +1,143 @@ +// 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. + +import 'dart:typed_data'; + +const _iv = [ + 0x6a09e667, + 0xbb67ae85, + 0x3c6ef372, + 0xa54ff53a, + 0x510e527f, + 0x9b05688c, + 0x1f83d9ab, + 0x5be0cd19, +]; + +const _permutation = [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8]; + +/// Test-only, deliberately direct implementation of unkeyed BLAKE3-256. +/// +/// Algorithm: https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf +/// +/// This uses recursive tree construction, byte-wise input/output, and looped +/// compression. It shares no code, generated schedules, or tree machinery with +/// the optimized implementations. Official vectors validate this oracle too. +Uint8List referenceBlake3(Uint8List input) { + var output = _subtree(input, 0, input.length); + var words = _compress( + output.cv, + output.block, + 0, + output.length, + output.flags | 8, // ROOT uses output-block counter zero. + ); + return Uint8List.fromList([ + for (var i = 0; i < 32; i++) (words[i ~/ 4] >>> (8 * (i % 4))) & 255, + ]); +} + +List<int> _compress( + List<int> cv, + List<int> block, + int counter, + int length, + int flags, +) { + var state = [ + ...cv, + ..._iv.take(4), + counter & 0xffffffff, + counter ~/ 0x100000000, + length, + flags, + ]; + var message = block; + for (var round = 0; round < 7; round++) { + for (var column = 0; column < 4; column++) { + _mix( + state, + column, + column + 4, + column + 8, + column + 12, + message[column * 2], + message[column * 2 + 1], + ); + } + for (var diagonal = 0; diagonal < 4; diagonal++) { + _mix( + state, + diagonal, + 4 + (diagonal + 1) % 4, + 8 + (diagonal + 2) % 4, + 12 + (diagonal + 3) % 4, + message[8 + diagonal * 2], + message[9 + diagonal * 2], + ); + } + message = [for (var index in _permutation) message[index]]; + } + return [ + for (var i = 0; i < 8; i++) state[i] ^ state[i + 8], + for (var i = 0; i < 8; i++) state[i + 8] ^ cv[i], + ]; +} + +void _mix(List<int> v, int a, int b, int c, int d, int x, int y) { + v[a] = (v[a] + v[b] + x) & 0xffffffff; + v[d] = _rotate(v[d] ^ v[a], 16); + v[c] = (v[c] + v[d]) & 0xffffffff; + v[b] = _rotate(v[b] ^ v[c], 12); + v[a] = (v[a] + v[b] + y) & 0xffffffff; + v[d] = _rotate(v[d] ^ v[a], 8); + v[c] = (v[c] + v[d]) & 0xffffffff; + v[b] = _rotate(v[b] ^ v[c], 7); +} + +int _rotate(int value, int amount) => + ((value >>> amount) | (value << (32 - amount))) & 0xffffffff; + +_Output _subtree(Uint8List bytes, int start, int end) { + var length = end - start; + if (length > 1024) { + // The left child is the largest complete power-of-two subtree strictly + // smaller than this tree. This also handles an incomplete rightmost chunk. + var leftLength = 1024; + while (leftLength * 2 < length) { + leftLength *= 2; + } + var left = _subtree(bytes, start, start + leftLength).chainingValue(); + var right = _subtree(bytes, start + leftLength, end).chainingValue(); + return _Output(_iv, [...left, ...right], 0, 64, 4); // PARENT + } + var cv = _iv; + var offset = start; + while (true) { + var count = end - offset < 64 ? end - offset : 64; + var block = List<int>.filled(16, 0); + for (var i = 0; i < count; i++) { + block[i ~/ 4] |= bytes[offset + i] << (8 * (i % 4)); + } + var last = offset + count == end; + var flags = (offset == start ? 1 : 0) | (last ? 2 : 0); + var output = _Output(cv, block, start ~/ 1024, count, flags); + if (last) return output; + cv = output.chainingValue(); + offset += count; + } +} + +class _Output { + final List<int> cv; + final List<int> block; + final int counter; + final int length; + final int flags; + + new(this.cv, this.block, this.counter, this.length, this.flags); + + List<int> chainingValue() => + _compress(cv, block, counter, length, flags).sublist(0, 8); +}
diff --git a/pkg/analyzer/test/src/utilities/hash/blake3_test.dart b/pkg/analyzer/test/src/utilities/hash/blake3_test.dart new file mode 100644 index 0000000..915aa71 --- /dev/null +++ b/pkg/analyzer/test/src/utilities/hash/blake3_test.dart
@@ -0,0 +1,365 @@ +// 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. + +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:analyzer/src/utilities/hash/blake3.dart'; +import 'package:test/test.dart'; + +import 'blake3_reference.dart'; + +void main() { + // Avoid dart:mirrors so the same suite can run in AOT as well as JIT. + group('Blake3', () { + late Blake3Test suite; + setUp(() => suite = Blake3Test()); + test('official vectors', () => suite.test_officialVectors()); + test( + 'block and tree boundaries', + () => suite.test_blockAndTreeBoundaries(), + ); + test('offset views', () => suite.test_offsetViews()); + test( + 'random and structured inputs', + () => suite.test_randomAndStructuredInputs(), + ); + test('reuse and ownership', () => suite.test_reuseAndOwnership()); + test('streaming official vectors', () => suite.test_streamingVectors()); + test('streaming split boundaries', () => suite.test_streamingSplits()); + test('streaming tree boundaries', () => suite.test_streamingTrees()); + test('streaming input views', () => suite.test_streamingViews()); + test('streaming lifecycle', () => suite.test_streamingLifecycle()); + }); +} + +/// Unkeyed 32-byte prefixes from upstream BLAKE3 1.8.7 test vectors (CC0). +/// +/// https://github.com/BLAKE3-team/BLAKE3/blob/f3149ec5bb5449af877ba20377a11008ff499fa2/test_vectors/test_vectors.json +/// +/// Input byte i is i % 251. These fixed expectations are not generated by any +/// Dart implementation. Tests need neither native code nor an upstream checkout. +const _blake3Vectors = <int, String>{ + 0: 'af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262', + 1: '2d3adedff11b61f14c886e35afa036736dcd87a74d27b5c1510225d0f592e213', + 2: '7b7015bb92cf0b318037702a6cdd81dee41224f734684c2c122cd6359cb1ee63', + 3: 'e1be4d7a8ab5560aa4199eea339849ba8e293d55ca0a81006726d184519e647f', + 4: 'f30f5ab28fe047904037f77b6da4fea1e27241c5d132638d8bedce9d40494f32', + 5: 'b40b44dfd97e7a84a996a91af8b85188c66c126940ba7aad2e7ae6b385402aa2', + 6: '06c4e8ffb6872fad96f9aaca5eee1553eb62aed0ad7198cef42e87f6a616c844', + 7: '3f8770f387faad08faa9d8414e9f449ac68e6ff0417f673f602a646a891419fe', + 8: '2351207d04fc16ade43ccab08600939c7c1fa70a5c0aaca76063d04c3228eaeb', + 63: 'e9bc37a594daad83be9470df7f7b3798297c3d834ce80ba85d6e207627b7db7b', + 64: '4eed7141ea4a5cd4b788606bd23f46e212af9cacebacdc7d1f4c6dc7f2511b98', + 65: 'de1e5fa0be70df6d2be8fffd0e99ceaa8eb6e8c93a63f2d8d1c30ecb6b263dee', + 127: 'd81293fda863f008c09e92fc382a81f5a0b4a1251cba1634016a0f86a6bd640d', + 128: 'f17e570564b26578c33bb7f44643f539624b05df1a76c81f30acd548c44b45ef', + 129: '683aaae9f3c5ba37eaaf072aed0f9e30bac0865137bae68b1fde4ca2aebdcb12', + 1023: '10108970eeda3eb932baac1428c7a2163b0e924c9a9e25b35bba72b28f70bd11', + 1024: '42214739f095a406f3fc83deb889744ac00df831c10daa55189b5d121c855af7', + 1025: 'd00278ae47eb27b34faecf67b4fe263f82d5412916c1ffd97c8cb7fb814b8444', + 2048: 'e776b6028c7cd22a4d0ba182a8bf62205d2ef576467e838ed6f2529b85fba24a', + 2049: '5f4d72f40d7a5f82b15ca2b2e44b1de3c2ef86c426c95c1af0b6879522563030', + 3072: 'b98cb0ff3623be03326b373de6b9095218513e64f1ee2edd2525c7ad1e5cffd2', + 3073: '7124b49501012f81cc7f11ca069ec9226cecb8a2c850cfe644e327d22d3e1cd3', + 4096: '015094013f57a5277b59d8475c0501042c0b642e531b0a1c8f58d2163229e969', + 4097: '9b4052b38f1c5fc8b1f9ff7ac7b27cd242487b3d890d15c96a1c25b8aa0fb995', + 5120: '9cadc15fed8b5d854562b26a9536d9707cadeda9b143978f319ab34230535833', + 5121: '628bd2cb2004694adaab7bbd778a25df25c47b9d4155a55f8fbd79f2fe154cff', + 6144: '3e2e5b74e048f3add6d21faab3f83aa44d3b2278afb83b80b3c35164ebeca205', + 6145: 'f1323a8631446cc50536a9f705ee5cb619424d46887f3c376c695b70e0f0507f', + 7168: '61da957ec2499a95d6b8023e2b0e604ec7f6b50e80a9678b89d2628e99ada77a', + 7169: 'a003fc7a51754a9b3c7fae0367ab3d782dccf28855a03d435f8cfe74605e7817', + 8192: 'aae792484c8efe4f19e2ca7d371d8c467ffb10748d8a5a1ae579948f718a2a63', + 8193: 'bab6c09cb8ce8cf459261398d2e7aef35700bf488116ceb94a36d0f5f1b7bc3b', + 16384: 'f875d6646de28985646f34ee13be9a576fd515f76b5b0a26bb324735041ddde4', + 31744: '62b6960e1a44bcc1eb1a611a8d6235b6b4b78f32e7abc4fb4c6cdcce94895c47', + 102400: 'bc3e3d41a1146b069abffad3c0d44860cf664390afce4d9661f7902e7943e085', +}; + +class Blake3Test { + final hasher = ScalarBlake3(); + + /// Checks empty input, and also lengths immediately before, at, and after 64-byte + /// block and 1024-byte chunk boundaries against the independent reference. + /// Chunk counts around powers of two exercise both complete and incomplete + /// trees, including reductions that merge several pending subtrees. + void test_blockAndTreeBoundaries() { + var lengths = { + 0, + for (var block = 1; block <= 129; block++) + for (final delta in [-1, 0, 1]) block * 64 + delta, + for (final chunks in [ + for (var i = 1; i <= 20; i++) i, + 31, + 32, + 33, + 63, + 64, + 65, + 127, + 128, + 129, + 255, + 256, + 257, + 511, + 512, + 513, + ]) + for (final delta in [-1, 0, 1]) chunks * 1024 + delta, + }; + var random = Random(538901); + var bytes = _randomBytes(random, lengths.reduce(max)); + for (var length in lengths) { + _check(Uint8List.sublistView(bytes, 0, length)); + } + } + + void test_officialVectors() { + for (var entry in _blake3Vectors.entries) { + var input = Uint8List.fromList([ + for (var i = 0; i < entry.key; i++) i % 251, + ]); + var expected = _decodeHex(entry.value); + expect( + referenceBlake3(input), + expected, + reason: 'reference ${entry.key}', + ); + _check(input, expected: expected); + } + } + + /// Hashes the same bytes at offsets 0..31 to cover aligned and unaligned views. + /// Each view must match the digest of a standalone input, excluding the + /// surrounding sentinel bytes. Comparing the entire backing buffer afterward + /// checks that neither the input nor the sentinel bytes were modified. + void test_offsetViews() { + var random = Random(29); + for (var length in [ + 0, + 1, + 63, + 64, + 65, + 1023, + 1024, + 1025, + 4095, + 4096, + 4097, + 65537, + ]) { + var bytes = _randomBytes(random, length); + var expected = referenceBlake3(bytes); + for (var offset = 0; offset < 32; offset++) { + var backing = Uint8List(length + 64)..fillRange(0, length + 64, 0xa5); + backing.setRange(offset, offset + length, bytes); + var before = Uint8List.fromList(backing); + _check( + Uint8List.sublistView(backing, offset, offset + length), + expected: expected, + ); + expect( + backing, + before, + reason: 'input/sentinels $length offset $offset', + ); + } + } + } + + void test_randomAndStructuredInputs() { + var random = Random(20260920); + for (var i = 0; i < 64; i++) { + _check(_randomBytes(random, random.nextInt(20000))); + } + for (var length in [1, 65, 1024, 2049, 8192, 262145]) { + for (var value in [0, 0x80, 0xff]) { + _check(Uint8List(length)..fillRange(0, length, value)); + } + } + } + + /// Checks that one hasher can process differently sized, unmodifiable inputs + /// while keeping every returned digest independently owned. Empty and small + /// inputs after large inputs exercise the reset of reusable scratch storage. + /// Mutating the input buffers and making later hash calls must leave saved + /// digests intact. Mutating one digest must not affect other digests or the + /// result of a subsequent hash call. + void test_reuseAndOwnership() { + var random = Random(7); + var saved = <(Uint8List, Uint8List)>[]; + for (var length in [524289, 0, 1, 1024, 63, 8193, 0, 65, 4096]) { + var bytes = _randomBytes(random, length); + var expected = referenceBlake3(bytes); + var digest = hasher.hash(bytes.asUnmodifiableView()); + expect(digest, expected); + expect(digest.length, 32); + saved.add((digest, Uint8List.fromList(digest))); + bytes.fillRange(0, length, 0); + } + for (var (digest, expected) in saved) { + expect(digest, expected, reason: 'retained digest changed'); + } + saved.last.$1.fillRange(0, 32, 0); + expect(hasher.hash(Uint8List(0)), _decodeHex(_blake3Vectors[0]!)); + for (var (digest, expected) in saved.take(saved.length - 1)) { + expect(digest, expected, reason: 'digest storage aliases'); + } + } + + void test_streamingLifecycle() { + var sink = ScalarBlake3Sink(); + var expected = referenceBlake3(Uint8List.fromList([1, 2, 3])); + var input = Uint8List.fromList([1, 2, 3]); + sink.add(input); + input.fillRange(0, input.length, 0); + var first = sink.finish(); + expect(first, expected); + var saved = sink.finish(); + first.fillRange(0, first.length, 0); + expect(sink.finish(), expected); + var empty = Uint8List(0); + var next = Uint8List.fromList([4]); + expect(() => sink.add(empty), throwsStateError); + expect(() => sink.add(next), throwsStateError); + + for (var length in [65537, 0, 64, 1, 1024, 1025, 0]) { + sink.reset(); + var bytes = Uint8List.fromList([ + for (var i = 0; i < length; i++) i & 255, + ]); + sink.add(bytes); + expect(sink.finish(), referenceBlake3(bytes)); + expect(saved, expected); + } + sink.reset(); + sink.add(Uint8List(4097)); + sink.reset(); + expect(sink.finish(), referenceBlake3(Uint8List(0))); + + sink.reset(); + sink.add(Uint8List.fromList([1, 2, 3])); + expect(sink.finish(), expected); + } + + void test_streamingSplits() { + var sink = ScalarBlake3Sink(); + var empty = Uint8List(0); + var random = Random(563962); + for (var length in [ + 0, + 1, + 63, + 64, + 65, + 127, + 128, + 129, + 1023, + 1024, + 1025, + 2048, + 2049, + ]) { + var input = _randomBytes(random, length); + var expected = referenceBlake3(input); + for (var split = 0; split <= length; split++) { + sink.reset(); + sink.add(Uint8List.sublistView(input, 0, split)); + sink.add(empty); + sink.add(Uint8List.sublistView(input, split, length)); + expect(sink.finish(), expected, reason: '$length split $split'); + } + } + } + + void test_streamingTrees() { + var random = Random(17); + var sink = ScalarBlake3Sink(); + for (var chunks in [3, 4, 7, 8, 15, 16, 31, 32, 127, 128, 255, 256]) { + for (var delta in [-1, 0, 1]) { + var input = _randomBytes(random, chunks * 1024 + delta); + sink.reset(); + for (var start = 0; start < input.length;) { + var end = min(input.length, start + 1 + random.nextInt(8192)); + sink.add(Uint8List.sublistView(input, start, end)); + start = end; + } + expect(sink.finish(), referenceBlake3(input)); + } + } + } + + void test_streamingVectors() { + var sink = ScalarBlake3Sink(); + for (var entry in _blake3Vectors.entries) { + var input = Uint8List.fromList([ + for (var i = 0; i < entry.key; i++) i % 251, + ]); + var expected = _decodeHex(entry.value); + for (var size in [1, 3, 4, 63, 64, 65, 1023, 1024, 1025, 16384]) { + sink.reset(); + for (var start = 0; start < input.length; start += size) { + sink.add( + Uint8List.sublistView( + input, + start, + min(start + size, input.length), + ), + ); + } + expect(sink.finish(), expected, reason: '${entry.key} pieces of $size'); + } + } + } + + void test_streamingViews() { + var random = Random(42); + for (var length in [0, 63, 64, 65, 1023, 1024, 1025, 4097]) { + var input = _randomBytes(random, length); + var expected = referenceBlake3(input); + for (var offset = 0; offset < 32; offset++) { + var backing = Uint8List(length + 64)..fillRange(0, length + 64, 0xa5); + backing.setRange(offset, offset + length, input); + var original = Uint8List.fromList(backing); + var view = Uint8List.sublistView(backing, offset, offset + length); + var sink = ScalarBlake3Sink(); + sink.add(view.asUnmodifiableView()); + expect(backing, original); + backing.fillRange(0, backing.length, 0); + expect(sink.finish(), expected); + + sink.reset(); + sink.add( + Uint8List.sublistView( + original.asUnmodifiableView(), + offset, + offset + length, + ), + ); + expect(sink.finish(), expected); + } + } + } + + void _check(Uint8List input, {Uint8List? expected}) { + expected ??= referenceBlake3(input); + expect( + hasher.hash(input), + expected, + reason: 'length ${input.length}, offset ${input.offsetInBytes}', + ); + } + + Uint8List _decodeHex(String hex) => Uint8List.fromList([ + for (var i = 0; i < hex.length; i += 2) + int.parse(hex.substring(i, i + 2), radix: 16), + ]); + + Uint8List _randomBytes(Random random, int length) => + Uint8List.fromList(List.generate(length, (_) => random.nextInt(256))); +}
diff --git a/pkg/analyzer/test/src/utilities/hash/test_all.dart b/pkg/analyzer/test/src/utilities/hash/test_all.dart new file mode 100644 index 0000000..b3cbf81 --- /dev/null +++ b/pkg/analyzer/test/src/utilities/hash/test_all.dart
@@ -0,0 +1,13 @@ +// 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. + +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import 'blake3_test.dart' as blake3; + +main() { + defineReflectiveSuite(() { + blake3.main(); + }, name: 'hash'); +}
diff --git a/pkg/analyzer/test/src/utilities/test_all.dart b/pkg/analyzer/test/src/utilities/test_all.dart index 71f0f25..710d08b 100644 --- a/pkg/analyzer/test/src/utilities/test_all.dart +++ b/pkg/analyzer/test/src/utilities/test_all.dart
@@ -6,10 +6,12 @@ import 'extensions/test_all.dart' as extensions; import 'fuzzy_matcher_test.dart' as fuzzy_matcher; +import 'hash/test_all.dart' as hash; main() { defineReflectiveSuite(() { extensions.main(); fuzzy_matcher.main(); + hash.main(); }, name: 'utilities'); }
diff --git a/pkg/analyzer/tool/blake3/generate.dart b/pkg/analyzer/tool/blake3/generate.dart new file mode 100644 index 0000000..20c8cfd --- /dev/null +++ b/pkg/analyzer/tool/blake3/generate.dart
@@ -0,0 +1,92 @@ +// 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. + +/// Generates the fixed-schedule, unrolled scalar BLAKE3 compression kernel. +library; + +import 'dart:io'; + +void main() { + const permutation = [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8]; + const groups = [ + (0, 4, 8, 12), + (1, 5, 9, 13), + (2, 6, 10, 14), + (3, 7, 11, 15), + (0, 5, 10, 15), + (1, 6, 11, 12), + (2, 7, 8, 13), + (3, 4, 9, 14), + ]; + var out = StringBuffer(''' +// 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. + +// Generated by pkg/analyzer/tool/blake3/generate.dart. Do not edit. + +part of 'blake3.dart'; +'''); + + out.write(''' +/// Compresses one 64-byte block with four independent scalar chains. +final class _ScalarBlake3 extends _Blake3Base implements ScalarBlake3 { +@override +void _compress(Uint32List cv, Uint32List words, int offset, + int counter, int blockLength, int flags) { +'''); + for (var i = 0; i < 8; i++) { + out.writeln('var v$i = cv[$i];'); + } + for (var i = 8; i < 12; i++) { + out.writeln('var v$i = _blake3Iv[${i - 8}];'); + } + out.write(''' +var v12 = counter & 0xffffffff; +var v13 = counter >>> 32; +var v14 = blockLength; +var v15 = flags; +'''); + for (var i = 0; i < 16; i++) { + out.writeln('var m$i = words[offset + $i];'); + } + var schedule = List.generate(16, (i) => i); + for (var round = 0; round < 7; round++) { + out.writeln(); + out.writeln('// Round ${round + 1}.'); + for (var (j, (a, b, c, d)) in groups.indexed) { + if (j > 0) { + out.writeln(); + } + out.writeln('// g($a, $b, $c, $d), permutation #$round'); + for (var (word, r1, r2) in [ + (schedule[2 * j], 16, 12), + (schedule[2 * j + 1], 8, 7), + ]) { + out.write(''' +v$a = (v$a + v$b + m$word) & 0xffffffff; +v$d ^= v$a; +v$d = ((v$d >>> $r1) | (v$d << ${32 - r1})) & 0xffffffff; +v$c = (v$c + v$d) & 0xffffffff; +v$b ^= v$c; +v$b = ((v$b >>> $r2) | (v$b << ${32 - r2})) & 0xffffffff; +'''); + } + } + schedule = [for (var i in permutation) schedule[i]]; + } + for (var i = 0; i < 8; i++) { + out.writeln('cv[$i] = v$i ^ v${i + 8};'); + } + out.write(''' +} +} +'''); + var output = File.fromUri( + Platform.script.resolve( + '../../lib/src/utilities/hash/blake3_scalar_compression.dart', + ), + ); + output.writeAsStringSync(out.toString()); +}
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_dart_3_12_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_dart_3_12_test.dart index d9b49aa..da4a70b 100644 --- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_dart_3_12_test.dart +++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_dart_3_12_test.dart
@@ -88,16 +88,13 @@ expression: 'x', // See: https://github.com/dart-lang/sdk/issues/63842. expectedError: - "Failed to read the 'x' property from 'Object': " - "Cannot access 'x' from debugger", + "The variable 'x' is unavailable in this expression evaluation.", ); await driver.checkInFrame( breakpointId: 'bp1', expression: '_x', // See: https://github.com/dart-lang/sdk/issues/63842. - expectedError: - "Failed to read the 'x' property from 'Object': " - "Cannot access 'x' from debugger", + expectedResult: 'null', ); }); test('private named parameter', () async { @@ -106,16 +103,16 @@ expression: 'x', // See: https://github.com/dart-lang/sdk/issues/63842. expectedError: - "Failed to read the 'x' property from 'Object': " - "Cannot access 'x' from debugger", + "DartError: NoSuchMethodError: 'x'\n" + 'method not found\n' + "Receiver: Instance of 'C2'\n" + 'Arguments: []\n', ); await driver.checkInFrame( breakpointId: 'bp3', expression: '_x', // See: https://github.com/dart-lang/sdk/issues/63842. - expectedError: - "Failed to read the 'x' property from 'Object': " - "Cannot access 'x' from debugger", + expectedResult: 'null', ); }); }); @@ -168,16 +165,13 @@ expression: 'x', // See: https://github.com/dart-lang/sdk/issues/63842. expectedError: - "Failed to read the 'x' property from 'Object': " - "Cannot access 'x' from debugger", + "The variable 'x' is unavailable in this expression evaluation.", ); await driver.checkInFrame( breakpointId: 'bp1', expression: '_x', // See: https://github.com/dart-lang/sdk/issues/63842. - expectedError: - "Failed to read the 'x' property from 'Object': " - "Cannot access 'x' from debugger", + expectedResult: 'null', ); }); test('private named parameter', () async { @@ -185,17 +179,13 @@ breakpointId: 'bp3', expression: 'x', // See: https://github.com/dart-lang/sdk/issues/63842. - expectedError: - "Failed to read the 'x' property from 'Object': " - "Cannot access 'x' from debugger", + expectedResult: '99', ); await driver.checkInFrame( breakpointId: 'bp3', expression: '_x', // See: https://github.com/dart-lang/sdk/issues/63842. - expectedError: - "Failed to read the 'x' property from 'Object': " - "Cannot access 'x' from debugger", + expectedResult: 'null', ); }); });
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart index 4268505..fb30921 100644 --- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart +++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
@@ -997,6 +997,10 @@ ownProperties: true, ); for (var prop in response) { + // Variables whose values are unavailable (e.g. stack-allocated in an + // outer function and not captured by the paused closure) are reported + // without a value. + if (prop.value == null) continue; var propKey = prop.name; var propValue = '${prop.value?.value}'; if (prop.value?.type == 'string') {
diff --git a/tests/modular/js_interop_annotation_name/base.dart b/tests/modular/js_interop_annotation_name/base.dart new file mode 100644 index 0000000..f8ae284 --- /dev/null +++ b/tests/modular/js_interop_annotation_name/base.dart
@@ -0,0 +1,8 @@ +// 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. + +class Base { + static const String memberName = 'baseMember'; + static const String exportName = 'baseExport'; +}
diff --git a/tests/modular/js_interop_annotation_name/main.dart b/tests/modular/js_interop_annotation_name/main.dart new file mode 100644 index 0000000..3236e58 --- /dev/null +++ b/tests/modular/js_interop_annotation_name/main.dart
@@ -0,0 +1,35 @@ +// 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. + +// Test that constant `@JS` and `@JSExport` values can be fetched modularly. + +import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; + +import 'package:expect/expect.dart'; + +import 'mid.dart'; + +void main() { + addTopLevel(); + // Interpolating `topLevelConstantName` here is intentional. See `mid.dart`. + eval("globalThis.$topLevelConstantName = 'topLevelConstant';"); + eval(''' + globalThis.JSClass = function() {}; + globalThis.JSClass.prototype.baseMember = function() { + return 'baseMember'; + }; + '''); + + Expect.equals('topLevel', topLevel); + Expect.equals('topLevelConstant', topLevelConstant); + Expect.equals('baseMember', JSClass().member()); + + final wrapper = createJSInteropWrapper(Export()); + Expect.isTrue(wrapper.has(Mid.exportName)); + Expect.equals( + 'baseExport', + wrapper.callMethod<JSString>(Mid.exportName.toJS).toDart, + ); +}
diff --git a/tests/modular/js_interop_annotation_name/mid.dart b/tests/modular/js_interop_annotation_name/mid.dart new file mode 100644 index 0000000..66b42b2 --- /dev/null +++ b/tests/modular/js_interop_annotation_name/mid.dart
@@ -0,0 +1,51 @@ +// 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. + +import 'dart:js_interop'; + +import 'base.dart'; + +@JS() +external void eval(String code); + +const String topLevelName = '$topLevelNamePrefix$topLevelNameSuffix'; +const String topLevelNamePrefix = 'topLevel'; +const String topLevelNameSuffix = 'Suffix'; + +const String topLevelConstantName = 'topLevelConstant'; + +class Mid { + static const String memberName = Base.memberName; + static const String exportName = Base.exportName; +} + +// Test that not constant-evaluated string interpolation works as intended. +// Since `main.dart` doesn't use `topLevelName`, this will stay as an +// unevaluated value. +@JS(topLevelName) +external String get topLevel; + +// Test that constant-evaluated string works as intended. Since `main.dart` does +// use `topLevelConstantName`, this will be evaluated. +@JS(topLevelConstantName) +external String get topLevelConstant; + +@JS() +extension type JSClass._(JSObject _) implements JSObject { + external JSClass(); + + // Test that recursive unevaluated strings work as intended. + @JS(Base.memberName) + external String member(); +} + +class Export { + // Same test as `member` but for `@JSExport`. + @JSExport(Mid.exportName) + String export() => 'baseExport'; +} + +void addTopLevel() { + eval("globalThis.$topLevelName = 'topLevel';"); +}
diff --git a/tests/modular/js_interop_annotation_name/modules.yaml b/tests/modular/js_interop_annotation_name/modules.yaml new file mode 100644 index 0000000..eb6033e --- /dev/null +++ b/tests/modular/js_interop_annotation_name/modules.yaml
@@ -0,0 +1,9 @@ +# 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. +# +# Test that `@JS` and `@JSExport` values can be evaluated constants, recursive +# gets, and string concatenation. +dependencies: + main: [mid, expect] + mid: base
diff --git a/tools/VERSION b/tools/VERSION index b715d30..a56cc3391 100644 --- a/tools/VERSION +++ b/tools/VERSION
@@ -27,5 +27,5 @@ MAJOR 3 MINOR 15 PATCH 0 -PRERELEASE 73 +PRERELEASE 74 PRERELEASE_PATCH 0