From a54b3f0a3ec6869fdeb93faa4dfb042cfd1c69c0 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Mon, 5 Apr 2021 18:26:09 -0700 Subject: [PATCH] Fix failing breakpoints in library part files and data race - Record library part paths in debugger tables properly. Make sure that we have module and library recorded for part scripts, in `MetadataProvider` and `Modules`, - Calculate locations for module atomically in `Locations`. This fixes intermittent 'Oh, snap!' in chrome due to a data race in location computation if several breakpoints are set in the same dart library. - Update test fixtures to include part files. - Add tests for frontend server and build runner scenarios. Closes: https://github.com/dart-lang/webdev/issues/1271 --- dwds/CHANGELOG.md | 2 + dwds/lib/src/debugging/inspector.dart | 8 +- dwds/lib/src/debugging/location.dart | 107 ++++----- dwds/lib/src/debugging/metadata/provider.dart | 6 +- dwds/lib/src/debugging/modules.dart | 27 ++- dwds/test/build_daemon_evaluate_test.dart | 69 +++++- dwds/test/frontend_server_evaluate_test.dart | 204 ++++++++++++++++++ fixtures/_testPackage/lib/src/test_part.dart | 23 ++ fixtures/_testPackage/lib/test_library.dart | 2 + fixtures/_testPackage/web/main.dart | 19 +- .../_testPackageSound/lib/src/test_part.dart | 23 ++ .../_testPackageSound/lib/test_library.dart | 2 + fixtures/_testPackageSound/web/main.dart | 21 +- 13 files changed, 438 insertions(+), 75 deletions(-) create mode 100644 fixtures/_testPackage/lib/src/test_part.dart create mode 100644 fixtures/_testPackageSound/lib/src/test_part.dart diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index f0d01bc3e..2db505d3a 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -3,6 +3,8 @@ - Support `vm_service` version `6.2.0`. - Fix missing sdk libraries in `getObject()` calls. - Fix incorrect `rootLib` returned by `ChromeProxyService`. +- Fix not working breakpoints in library part files. +- Fix data race in calculating locations for a module. ## 10.0.1 diff --git a/dwds/lib/src/debugging/inspector.dart b/dwds/lib/src/debugging/inspector.dart index 06656456e..bfee68a1c 100644 --- a/dwds/lib/src/debugging/inspector.dart +++ b/dwds/lib/src/debugging/inspector.dart @@ -5,7 +5,6 @@ // @dart = 2.9 import 'package:logging/logging.dart'; -import 'package:path/path.dart' as p; import 'package:vm_service/vm_service.dart'; import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; @@ -88,6 +87,9 @@ class AppInspector extends Domain { isolate.libraries.addAll(libraries); await DartUri.recordAbsoluteUris(libraries.map((lib) => lib.uri)); + var scripts = await _getScripts(); + await DartUri.recordAbsoluteUris(scripts.map((script) => script.uri)); + isolate.extensionRPCs.addAll(await _getExtensionRpcs()); } @@ -470,12 +472,10 @@ function($argsString) { // for them. var userLibraries = libraryUris.where((uri) => !uri.startsWith('dart:')); for (var uri in userLibraries) { - var parent = uri.substring(0, uri.lastIndexOf('/')); var parts = scripts[uri]; var scriptRefs = [ ScriptRef(uri: uri, id: createId()), - for (var part in parts) - ScriptRef(uri: p.url.join(parent, part), id: createId()) + for (var part in parts) ScriptRef(uri: part, id: createId()) ]; var libraryRef = await libraryHelper.libraryRefFor(uri); for (var scriptRef in scriptRefs) { diff --git a/dwds/lib/src/debugging/location.dart b/dwds/lib/src/debugging/location.dart index 274c35c7d..1159121b2 100644 --- a/dwds/lib/src/debugging/location.dart +++ b/dwds/lib/src/debugging/location.dart @@ -4,6 +4,7 @@ // @dart = 2.9 +import 'package:async/async.dart'; import 'package:path/path.dart' as p; import 'package:source_maps/parser.dart'; import 'package:source_maps/source_maps.dart'; @@ -105,16 +106,17 @@ class JsLocation { /// Contains meta data for known [Location]s. class Locations { - /// Map from Dart server path to all corresponding [Location] data. - final _sourceToLocation = >{}; + /// [Location] data for Dart server path. + final Map> _sourceToLocation = {}; + final Map>> _locationMemoizer = {}; - /// Map from Dart server path to tokenPosTable as defined in the + /// `tokenPosTable` for Dart server path, as defined in the /// Dart VM Service Protocol: /// https://github.com/dart-lang/sdk/blob/master/runtime/vm/service/service.md#script - final _sourceToTokenPosTable = >>{}; + final Map>> _sourceToTokenPosTable = {}; /// The set of all known [Location]s for a module. - final _moduleToLocations = >{}; + final Map> _moduleToLocations = {}; final AssetReader _assetReader; final Modules _modules; @@ -129,6 +131,7 @@ class Locations { void initialize(String entrypoint) { _sourceToTokenPosTable.clear(); _sourceToLocation.clear(); + _locationMemoizer.clear(); _moduleToLocations.clear(); _entrypoint = entrypoint; } @@ -136,8 +139,6 @@ class Locations { /// Returns all [Location] data for a provided Dart source. Future> locationsForDart(String serverPath) async { var module = await _modules.moduleForSource(serverPath); - var cache = _sourceToLocation[serverPath]; - if (cache != null) return cache; await _locationsForModule(module); return _sourceToLocation[serverPath] ?? {}; } @@ -202,50 +203,56 @@ class Locations { /// /// This will populate the [_sourceToLocation] and [_moduleToLocations] maps. Future> _locationsForModule(String module) async { - if (module == null) return {}; - if (_moduleToLocations[module] != null) return _moduleToLocations[module]; - var result = {}; - if (module?.isEmpty ?? true) return _moduleToLocations[module] = result; - if (module.endsWith('dart_sdk') || module.endsWith('dart_library')) { - return result; - } - var modulePath = - await globalLoadStrategy.serverPathForModule(_entrypoint, module); - var sourceMapPath = - await globalLoadStrategy.sourceMapPathForModule(_entrypoint, module); - var sourceMapContents = await _assetReader.sourceMapContents(sourceMapPath); - var scriptLocation = p.url.dirname('/$modulePath'); - if (sourceMapContents == null) return result; - // This happens to be a [SingleMapping] today in DDC. - var mapping = parse(sourceMapContents); - if (mapping is SingleMapping) { - // Create TokenPos for each entry in the source map. - for (var lineEntry in mapping.lines) { - for (var entry in lineEntry.entries) { - var index = entry.sourceUrlId; - if (index == null) continue; - // Source map URLS are relative to the script. They may have platform separators - // or they may use URL semantics. To be sure, we split and re-join them. - // This works on Windows because path treats both / and \ as separators. - // It will fail if the path has both separators in it. - var relativeSegments = p.split(mapping.urls[index]); - var path = p.url - .normalize(p.url.joinAll([scriptLocation, ...relativeSegments])); - var dartUri = DartUri(path, _root); - result.add(Location.from( - modulePath, - lineEntry, - entry, - dartUri, - )); + _locationMemoizer.putIfAbsent(module, () => AsyncMemoizer()); + + return await _locationMemoizer[module].runOnce(() async { + if (module == null) return {}; + if (_moduleToLocations[module] != null) return _moduleToLocations[module]; + var result = {}; + if (module?.isEmpty ?? true) return _moduleToLocations[module] = result; + if (module.endsWith('dart_sdk') || module.endsWith('dart_library')) { + return result; + } + var modulePath = + await globalLoadStrategy.serverPathForModule(_entrypoint, module); + var sourceMapPath = + await globalLoadStrategy.sourceMapPathForModule(_entrypoint, module); + var sourceMapContents = + await _assetReader.sourceMapContents(sourceMapPath); + var scriptLocation = p.url.dirname('/$modulePath'); + if (sourceMapContents == null) return result; + // This happens to be a [SingleMapping] today in DDC. + var mapping = parse(sourceMapContents); + if (mapping is SingleMapping) { + // Create TokenPos for each entry in the source map. + for (var lineEntry in mapping.lines) { + for (var entry in lineEntry.entries) { + var index = entry.sourceUrlId; + if (index == null) continue; + // Source map URLS are relative to the script. They may have platform separators + // or they may use URL semantics. To be sure, we split and re-join them. + // This works on Windows because path treats both / and \ as separators. + // It will fail if the path has both separators in it. + var relativeSegments = p.split(mapping.urls[index]); + var path = p.url.normalize( + p.url.joinAll([scriptLocation, ...relativeSegments])); + var dartUri = DartUri(path, _root); + result.add(Location.from( + modulePath, + lineEntry, + entry, + dartUri, + )); + } } } - } - for (var location in result) { - _sourceToLocation - .putIfAbsent(location.dartLocation.uri.serverPath, () => {}) - .add(location); - } - return _moduleToLocations[module] = result; + for (var location in result) { + _sourceToLocation + .putIfAbsent( + location.dartLocation.uri.serverPath, () => {}) + .add(location); + } + return _moduleToLocations[module] = result; + }); } } diff --git a/dwds/lib/src/debugging/metadata/provider.dart b/dwds/lib/src/debugging/metadata/provider.dart index 0f8080d26..335328094 100644 --- a/dwds/lib/src/debugging/metadata/provider.dart +++ b/dwds/lib/src/debugging/metadata/provider.dart @@ -9,6 +9,7 @@ import 'dart:convert'; import 'package:async/async.dart'; import 'package:logging/logging.dart'; +import 'package:path/path.dart' as p; import '../../readers/asset_reader.dart'; import 'module_metadata.dart'; @@ -233,7 +234,10 @@ class MetadataProvider { _scriptToModule[library.importUri] = metadata.name; for (var path in library.partUris) { - _scripts[library.importUri].add(path); + // parts in metadata are relative to the library Uri directory + var partPath = p.url.join(p.dirname(library.importUri), path); + _scripts[library.importUri].add(partPath); + _scriptToModule[partPath] = metadata.name; } } } diff --git a/dwds/lib/src/debugging/modules.dart b/dwds/lib/src/debugging/modules.dart index c62ae3962..1b6c2097e 100644 --- a/dwds/lib/src/debugging/modules.dart +++ b/dwds/lib/src/debugging/modules.dart @@ -73,15 +73,26 @@ class Modules { Future _initializeMapping() async { var provider = globalLoadStrategy.metadataProviderFor(_entrypoint); + var libraryToScripts = await provider.scripts; var scriptToModule = await provider.scriptToModule; - for (var script in scriptToModule.keys) { - var serverPath = script.startsWith('dart:') - ? script - : DartUri(script, _root).serverPath; - - _sourceToModule[serverPath] = scriptToModule[script]; - _sourceToLibrary[serverPath] = Uri.parse(script); - _libraryToModule[script] = scriptToModule[script]; + + for (var library in libraryToScripts.keys) { + var libraryServerPath = library.startsWith('dart:') + ? library + : DartUri(library, _root).serverPath; + + _sourceToModule[libraryServerPath] = scriptToModule[library]; + _sourceToLibrary[libraryServerPath] = Uri.parse(library); + _libraryToModule[library] = scriptToModule[library]; + + for (var script in libraryToScripts[library]) { + var scriptServerPath = script.startsWith('dart:') + ? script + : DartUri(script, _root).serverPath; + + _sourceToModule[scriptServerPath] = scriptToModule[library]; + _sourceToLibrary[scriptServerPath] = Uri.parse(library); + } } } } diff --git a/dwds/test/build_daemon_evaluate_test.dart b/dwds/test/build_daemon_evaluate_test.dart index 4f55a0b5b..2fc0e39be 100644 --- a/dwds/test/build_daemon_evaluate_test.dart +++ b/dwds/test/build_daemon_evaluate_test.dart @@ -85,6 +85,7 @@ void main() async { ScriptRef mainScript; ScriptRef libraryScript; ScriptRef testLibraryScript; + ScriptRef testLibraryPartScript; Stream stream; setUp(() async { @@ -99,6 +100,8 @@ void main() async { .firstWhere((each) => each.uri.contains('main.dart')); testLibraryScript = scripts.scripts.firstWhere((each) => each.uri.contains('package:_testPackage/test_library.dart')); + testLibraryPartScript = scripts.scripts.firstWhere((each) => + each.uri.contains('package:_testPackage/src/test_part.dart')); libraryScript = scripts.scripts.firstWhere( (each) => each.uri.contains('package:_test/library.dart')); }); @@ -125,7 +128,8 @@ void main() async { }); test('field', () async { - await onBreakPoint(isolate.id, mainScript, 'printField', () async { + await onBreakPoint( + isolate.id, mainScript, 'printFieldFromLibraryClass', () async { var event = await stream.firstWhere( (event) => event.kind == EventKind.kPauseBreakpoint); @@ -142,7 +146,8 @@ void main() async { }); test('private field from another library', () async { - await onBreakPoint(isolate.id, mainScript, 'printField', () async { + await onBreakPoint( + isolate.id, mainScript, 'printFieldFromLibraryClass', () async { var event = await stream.firstWhere( (event) => event.kind == EventKind.kPauseBreakpoint); @@ -177,7 +182,8 @@ void main() async { }); test('access instance fields after evaluation', () async { - await onBreakPoint(isolate.id, mainScript, 'printField', () async { + await onBreakPoint( + isolate.id, mainScript, 'printFieldFromLibraryClass', () async { var event = await stream.firstWhere( (event) => event.kind == EventKind.kPauseBreakpoint); @@ -267,6 +273,40 @@ void main() async { }); }); + test('call library part function with const param', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream.firstWhere( + (event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame(isolate.id, + event.topFrame.index, 'testLibraryPartFunction(42)'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, + 'valueAsString', + '42')); + }); + }); + + test('call library part function with local param', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream.firstWhere( + (event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame(isolate.id, + event.topFrame.index, 'testLibraryPartFunction(local)'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, + 'valueAsString', + '42')); + }); + }); + test('loop variable', () async { await onBreakPoint(isolate.id, mainScript, 'printLoopVariable', () async { @@ -303,7 +343,7 @@ void main() async { }); }); - test('evaluate expression in a class constructor in another library', + test('evaluate expression in a class constructor in a library', () async { await onBreakPoint( isolate.id, testLibraryScript, 'testLibraryClassConstructor', @@ -323,6 +363,25 @@ void main() async { }); }); + test('evaluate expression in a class constructor in a library part', + () async { + await onBreakPoint(isolate.id, testLibraryPartScript, + 'testLibraryPartClassConstructor', () async { + var event = await stream.firstWhere( + (event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'this.field'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, + 'valueAsString', + '1')); + }); + }); + test('evaluate expression in caller frame', () async { await onBreakPoint( isolate.id, testLibraryScript, 'testLibraryFunction', () async { @@ -341,7 +400,7 @@ void main() async { }); }); - test('evaluate expression in another library', () async { + test('evaluate expression in a library', () async { await onBreakPoint(isolate.id, libraryScript, 'Concatenate', () async { var event = await stream.firstWhere( diff --git a/dwds/test/frontend_server_evaluate_test.dart b/dwds/test/frontend_server_evaluate_test.dart index 1b1073999..fbb2edb89 100644 --- a/dwds/test/frontend_server_evaluate_test.dart +++ b/dwds/test/frontend_server_evaluate_test.dart @@ -77,6 +77,9 @@ void main() async { Isolate isolate; ScriptList scripts; ScriptRef mainScript; + ScriptRef libraryScript; + ScriptRef testLibraryScript; + ScriptRef testLibraryPartScript; Stream stream; setUp(() async { @@ -89,6 +92,12 @@ void main() async { mainScript = scripts.scripts .firstWhere((each) => each.uri.contains('main.dart')); + testLibraryScript = scripts.scripts.firstWhere((each) => + each.uri.contains('package:_testPackage/test_library.dart')); + testLibraryPartScript = scripts.scripts.firstWhere((each) => + each.uri.contains('package:_testPackage/src/test_part.dart')); + libraryScript = scripts.scripts.firstWhere( + (each) => each.uri.contains('package:_test/library.dart')); }); tearDown(() async { @@ -110,6 +119,90 @@ void main() async { }); }); + test('local', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'local'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '42')); + }); + }); + + test('field', () async { + await onBreakPoint(isolate.id, mainScript, 'printFieldFromLibraryClass', + () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'instance.field'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '1')); + }); + }); + + test('private field from another library', () async { + await onBreakPoint(isolate.id, mainScript, 'printFieldFromLibraryClass', + () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'instance._field'); + + expect( + result, + isA().having((instance) => instance.message, 'message', + contains("The getter '_field' isn't defined"))); + }); + }); + + test('private field from current library', () async { + await onBreakPoint(isolate.id, mainScript, 'printFieldMain', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'instance._field'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '1')); + }); + }); + + test('access instance fields after evaluation', () async { + await onBreakPoint(isolate.id, mainScript, 'printFieldFromLibraryClass', + () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var instanceRef = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'instance') as InstanceRef; + + var instance = await setup.service + .getObject(isolate.id, instanceRef.id) as Instance; + + var field = instance.fields + .firstWhere((BoundField element) => element.decl.name == 'field'); + + expect( + field.value, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '1')); + }); + }); + test('global', () async { await onBreakPoint(isolate.id, mainScript, 'printGlobal', () async { var event = await stream.firstWhere( @@ -172,6 +265,36 @@ void main() async { }); }); + test('call library part function with const param', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame( + isolate.id, event.topFrame.index, 'testLibraryPartFunction(42)'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '42')); + }); + }); + + test('call library part function with local param', () async { + await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service.evaluateInFrame(isolate.id, + event.topFrame.index, 'testLibraryPartFunction(local)'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '42')); + }); + }); + test('loop variable', () async { await onBreakPoint(isolate.id, mainScript, 'printLoopVariable', () async { @@ -188,6 +311,87 @@ void main() async { }); }); + test('evaluate expression in _testPackage/test_library', () async { + await onBreakPoint(isolate.id, testLibraryScript, 'testLibraryFunction', + () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'formal'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '23')); + }); + }); + + test('evaluate expression in a class constructor in a library', () async { + await onBreakPoint( + isolate.id, testLibraryScript, 'testLibraryClassConstructor', + () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'this.field'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '1')); + }); + }); + + test('evaluate expression in a class constructor in a library part', + () async { + await onBreakPoint(isolate.id, testLibraryPartScript, + 'testLibraryPartClassConstructor', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'this.field'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '1')); + }); + }); + + test('evaluate expression in caller frame', () async { + await onBreakPoint(isolate.id, testLibraryScript, 'testLibraryFunction', + () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index + 1, 'local'); + + expect( + result, + isA().having( + (instance) => instance.valueAsString, 'valueAsString', '23')); + }); + }); + + test('evaluate expression in a library', () async { + await onBreakPoint(isolate.id, libraryScript, 'Concatenate', () async { + var event = await stream + .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); + + var result = await setup.service + .evaluateInFrame(isolate.id, event.topFrame.index, 'a'); + + expect( + result, + isA().having((instance) => instance.valueAsString, + 'valueAsString', 'Hello')); + }); + }); + test('error', () async { await onBreakPoint(isolate.id, mainScript, 'printLocal', () async { var event = await stream.firstWhere( diff --git a/fixtures/_testPackage/lib/src/test_part.dart b/fixtures/_testPackage/lib/src/test_part.dart new file mode 100644 index 000000000..ae3429ea6 --- /dev/null +++ b/fixtures/_testPackage/lib/src/test_part.dart @@ -0,0 +1,23 @@ +// Copyright (c) 2019, 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 '../test_library.dart'; + +int testPartLibraryValue = 4; + +int testLibraryPartFunction(int formal) { + return formal; // Breakpoint: testLibraryPartFunction +} + +class TestLibraryPartClass { + final int field; + final int _field; + +TestLibraryPartClass(this.field, this._field) { + print('Contructor'); // Breakpoint: testLibraryPartClassConstructor + } + + @override + String toString() => 'field: $field, _field: $_field'; +} \ No newline at end of file diff --git a/fixtures/_testPackage/lib/test_library.dart b/fixtures/_testPackage/lib/test_library.dart index 8a2228cfe..c1004cb05 100644 --- a/fixtures/_testPackage/lib/test_library.dart +++ b/fixtures/_testPackage/lib/test_library.dart @@ -2,6 +2,8 @@ // 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 'src/test_part.dart'; + int testLibraryValue = 3; int testLibraryFunction(int formal) { diff --git a/fixtures/_testPackage/web/main.dart b/fixtures/_testPackage/web/main.dart index d52f01562..16e9128ae 100644 --- a/fixtures/_testPackage/web/main.dart +++ b/fixtures/_testPackage/web/main.dart @@ -24,15 +24,18 @@ void main() { Timer.periodic(const Duration(seconds: 1), (_) { print('Count is: ${++count}'); print(testLibraryValue); + print(testPartLibraryValue); }); // for evaluation Timer.periodic(const Duration(seconds: 1), (_) { printLocal(); - printField(); + printFieldFromLibraryClass(); + printFieldFromLibraryPartClass(); printFieldMain(); printGlobal(); printFromTestLibrary(); + printFromTestLibraryPart(); printFromTestPackage(); printCallExtension(); printLoopVariable(); @@ -46,9 +49,14 @@ void printLocal() { print('Local is: $local'); // Breakpoint: printLocal } -void printField() { +void printFieldFromLibraryClass() { var instance = TestLibraryClass(1, 2); - print('$instance'); // Breakpoint: printField + print('$instance'); // Breakpoint: printFieldFromLibraryClass +} + +void printFieldFromLibraryPartClass() { + var instance = TestLibraryPartClass(1, 2); + print('$instance'); // Breakpoint: printFieldFromLibraryPartClass } void printFieldMain() { @@ -69,6 +77,11 @@ void printFromTestLibrary() { print(testLibraryFunction(local)); } +void printFromTestLibraryPart() { + var local = 23; + print(testLibraryPartFunction(local)); +} + void printCallExtension() { var local = '23'; print(local.parseInt()); diff --git a/fixtures/_testPackageSound/lib/src/test_part.dart b/fixtures/_testPackageSound/lib/src/test_part.dart new file mode 100644 index 000000000..5c0e34865 --- /dev/null +++ b/fixtures/_testPackageSound/lib/src/test_part.dart @@ -0,0 +1,23 @@ +// Copyright (c) 2019, 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 '../test_library.dart'; + +int testPartLibraryValue = 4; + +int testLibraryPartFunction(int formal) { + return formal; // Breakpoint: testLibraryPartFunction +} + +class TestLibraryPartClass { + final int field; + final int _field; + + TestLibraryPartClass(this.field, this._field) { + print('Contructor'); // Breakpoint: testLibraryPartClassConstructor + } + + @override + String toString() => 'field: $field, _field: $_field'; +} \ No newline at end of file diff --git a/fixtures/_testPackageSound/lib/test_library.dart b/fixtures/_testPackageSound/lib/test_library.dart index 470474b75..087f25067 100644 --- a/fixtures/_testPackageSound/lib/test_library.dart +++ b/fixtures/_testPackageSound/lib/test_library.dart @@ -2,6 +2,8 @@ // 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 'src/test_part.dart'; + int testLibraryValue = 3; int testLibraryFunction(int formal) { diff --git a/fixtures/_testPackageSound/web/main.dart b/fixtures/_testPackageSound/web/main.dart index 14abf126e..5a86a486b 100644 --- a/fixtures/_testPackageSound/web/main.dart +++ b/fixtures/_testPackageSound/web/main.dart @@ -22,16 +22,19 @@ void main() async { Timer.periodic(const Duration(seconds: 1), (_) { print('Count is: ${++count}'); print(testLibraryValue); + print(testPartLibraryValue); }); // for evaluation Timer.periodic(const Duration(seconds: 1), (_) async { await asyncMethod(); - //printLocal(); - printField(); + printLocal(); + printFieldFromLibraryClass(); + printFieldFromLibraryPartClass(); printFieldMain(); printGlobal(); printFromTestLibrary(); + printFromTestLibraryPart(); printFromTestPackage(); printCallExtension(); printLoopVariable(); @@ -54,9 +57,14 @@ void printLocal() { print('Local is: $local'); // Breakpoint: printLocal } -void printField() { +void printFieldFromLibraryClass() { var instance = TestLibraryClass(1, 2); - print('$instance'); // Breakpoint: printField + print('$instance'); // Breakpoint: printFieldFromLibraryClass +} + +void printFieldFromLibraryPartClass() { + var instance = TestLibraryPartClass(1, 2); + print('$instance'); // Breakpoint: printFieldFromLibraryPartClass } void printFieldMain() { @@ -77,6 +85,11 @@ void printFromTestLibrary() { print(testLibraryFunction(local)); } +void printFromTestLibraryPart() { + var local = 23; + print(testLibraryPartFunction(local)); +} + void printCallExtension() { var local = '23'; print(local.parseInt());