From 935bda5d4d11676ccf5a0602d22ef3cb46173769 Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Wed, 24 Nov 2021 11:49:21 -0800 Subject: [PATCH 1/5] Add static fields to classes --- dwds/lib/src/debugging/classes.dart | 50 ++++++++++++++++++-- dwds/test/chrome_proxy_service_test.dart | 6 +++ fixtures/_test/example/hello_world/main.dart | 2 + 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/dwds/lib/src/debugging/classes.dart b/dwds/lib/src/debugging/classes.dart index c3fc1dbdb..fada7cc5f 100644 --- a/dwds/lib/src/debugging/classes.dart +++ b/dwds/lib/src/debugging/classes.dart @@ -117,7 +117,7 @@ class ClassHelper extends Domain { "isStatic": false, } } - // TODO(jakemac): static fields once ddc supports them + var fields = sdkUtils.getFields(clazz); var fieldNames = fields ? Object.keys(fields) : []; descriptor['fields'] = {}; @@ -135,6 +135,23 @@ class ClassHelper extends Domain { "classRefLibraryId" : field["type"][libraryUri], } } + + // TODO(elliette): The following static member information is minimal and + // should be replaced once DDC provides full symbol information (see + // https://github.com/dart-lang/sdk/issues/40273): + + descriptor['staticFields'] = {}; + var staticFieldNames = sdkUtils.getStaticFields(clazz) ?? []; + for (const name of staticFieldNames) { + descriptor['staticFields'][name] = { + "isStatic": true, + // DDC only provides names of static members, we set isConst/isFinal + // to false even though they could be true. + "isConst": false, + "isFinal": false, + } + } + return descriptor; })() '''; @@ -176,16 +193,39 @@ class ClassHelper extends Domain { name: name, owner: classRef, declaredType: InstanceRef( - identityHashCode: createId().hashCode, - id: createId(), - kind: InstanceKind.kType, - classRef: classMetaData.classRef), + identityHashCode: createId().hashCode, + id: createId(), + kind: InstanceKind.kType, + // TODO(elliette): Is this the same as classRef? + classRef: classMetaData.classRef, + ), isConst: descriptor['isConst'] as bool, isFinal: descriptor['isFinal'] as bool, isStatic: descriptor['isStatic'] as bool, id: createId())); }); + var staticFieldDescriptors = + classDescriptor['staticFields'] as Map; + staticFieldDescriptors.forEach((name, descriptor) async { + fieldRefs.add( + FieldRef( + name: name, + owner: classRef, + declaredType: InstanceRef( + identityHashCode: createId().hashCode, + id: createId(), + kind: InstanceKind.kType, + classRef: classRef, + ), + isConst: descriptor['isConst'] as bool, + isFinal: descriptor['isFinal'] as bool, + isStatic: descriptor['isStatic'] as bool, + id: createId(), + ), + ); + }); + // TODO: Implement the rest of these // https://github.com/dart-lang/webdev/issues/176. return Class( diff --git a/dwds/test/chrome_proxy_service_test.dart b/dwds/test/chrome_proxy_service_test.dart index 29e2f2283..72b0fc763 100644 --- a/dwds/test/chrome_proxy_service_test.dart +++ b/dwds/test/chrome_proxy_service_test.dart @@ -475,6 +475,12 @@ void main() { !f.isStatic && !f.isConst && !f.isFinal), + predicate((FieldRef f) => + f.name == 'staticMessage' && + f.declaredType != null && + f.isStatic && + !f.isConst && + !f.isFinal), ])); }); diff --git a/fixtures/_test/example/hello_world/main.dart b/fixtures/_test/example/hello_world/main.dart index 05f9cb195..5640cbb3e 100644 --- a/fixtures/_test/example/hello_world/main.dart +++ b/fixtures/_test/example/hello_world/main.dart @@ -117,6 +117,8 @@ class MyTestClass { String notFinal; + static final String staticMessage = 'static'; + MyTestClass({this.message = 'world'}); String hello() => message; From 634e169f2e0a18f7d12a0c120301b66ac8c5530d Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Wed, 24 Nov 2021 12:02:59 -0800 Subject: [PATCH 2/5] Add static methods to classes --- dwds/lib/src/debugging/classes.dart | 14 ++++++++++++++ dwds/test/chrome_proxy_service_test.dart | 1 + fixtures/_test/example/hello_world/main.dart | 2 ++ 3 files changed, 17 insertions(+) diff --git a/dwds/lib/src/debugging/classes.dart b/dwds/lib/src/debugging/classes.dart index fada7cc5f..7f258199e 100644 --- a/dwds/lib/src/debugging/classes.dart +++ b/dwds/lib/src/debugging/classes.dart @@ -152,6 +152,17 @@ class ClassHelper extends Domain { } } + descriptor['staticMethods'] = {}; + var staticMethodNames = sdkUtils.getStaticMethods(clazz) ?? []; + for (var name of staticMethodNames) { + descriptor['methods'][name] = { + // DDC only provides names of static members, we set isConst + // to false even though it could be true. + "isConst": false, + "isStatic": true, + } + } + return descriptor; })() '''; @@ -170,6 +181,9 @@ class ClassHelper extends Domain { var classDescriptor = result.value as Map; var methodRefs = []; var methodDescriptors = classDescriptor['methods'] as Map; + var staticMethodDescriptors = + classDescriptor['staticMethods'] as Map; + methodDescriptors.addAll(staticMethodDescriptors); methodDescriptors.forEach((name, descriptor) { var methodId = 'methods|${classRef.id}|$name'; methodRefs.add(FuncRef( diff --git a/dwds/test/chrome_proxy_service_test.dart b/dwds/test/chrome_proxy_service_test.dart index 72b0fc763..6c1fbc762 100644 --- a/dwds/test/chrome_proxy_service_test.dart +++ b/dwds/test/chrome_proxy_service_test.dart @@ -451,6 +451,7 @@ void main() { expect( testClass.functions, unorderedEquals([ + predicate((FuncRef f) => f.name == 'staticHello' && f.isStatic), predicate((FuncRef f) => f.name == 'message' && !f.isStatic), predicate((FuncRef f) => f.name == 'notFinal' && !f.isStatic), predicate((FuncRef f) => f.name == 'hello' && !f.isStatic), diff --git a/fixtures/_test/example/hello_world/main.dart b/fixtures/_test/example/hello_world/main.dart index 5640cbb3e..da0bd5a9d 100644 --- a/fixtures/_test/example/hello_world/main.dart +++ b/fixtures/_test/example/hello_world/main.dart @@ -119,6 +119,8 @@ class MyTestClass { static final String staticMessage = 'static'; + static String staticHello() => 'static hello'; + MyTestClass({this.message = 'world'}); String hello() => message; From e45a0261d2c3a9abf671699efe31345a455c9070 Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Tue, 30 Nov 2021 17:18:09 -0800 Subject: [PATCH 3/5] Updated CHANGELOG / skip tests --- dwds/CHANGELOG.md | 1 + dwds/test/chrome_proxy_service_test.dart | 89 +++++++++++++----------- 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index 1a92c2961..7c2ed1ad1 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -14,6 +14,7 @@ - Fix chrome detection in iPhone emulation mode in chrome or edge browsers. - Reliably find unused port for extension backend http service. - Ignore offset / count parameters in getObject if the object has no length +- Include static member information for classes ## 11.4.0 diff --git a/dwds/test/chrome_proxy_service_test.dart b/dwds/test/chrome_proxy_service_test.dart index 5f7311978..72de47a79 100644 --- a/dwds/test/chrome_proxy_service_test.dart +++ b/dwds/test/chrome_proxy_service_test.dart @@ -15,6 +15,7 @@ import 'package:dwds/src/services/chrome_proxy_service.dart'; import 'package:dwds/src/utilities/dart_uri.dart'; import 'package:http/http.dart' as http; import 'package:path/path.dart' as path; +import 'package:pub_semver/pub_semver.dart' as semver; import 'package:test/test.dart'; import 'package:vm_service/vm_service.dart'; import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; @@ -445,45 +446,55 @@ void main() { expect(library1, equals(library2)); }); - test('Classes', () async { - var testClass = await service.getObject( - isolate.id, rootLibrary.classes.first.id) as Class; - expect( - testClass.functions, - unorderedEquals([ - predicate((FuncRef f) => f.name == 'staticHello' && f.isStatic), - predicate((FuncRef f) => f.name == 'message' && !f.isStatic), - predicate((FuncRef f) => f.name == 'notFinal' && !f.isStatic), - predicate((FuncRef f) => f.name == 'hello' && !f.isStatic), - predicate((FuncRef f) => f.name == '_equals' && !f.isStatic), - predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic), - predicate((FuncRef f) => f.name == 'toString' && !f.isStatic), - predicate((FuncRef f) => f.name == 'noSuchMethod' && !f.isStatic), - predicate((FuncRef f) => f.name == 'runtimeType' && !f.isStatic), - ])); - expect( - testClass.fields, - unorderedEquals([ - predicate((FieldRef f) => - f.name == 'message' && - f.declaredType != null && - !f.isStatic && - !f.isConst && - f.isFinal), - predicate((FieldRef f) => - f.name == 'notFinal' && - f.declaredType != null && - !f.isStatic && - !f.isConst && - !f.isFinal), - predicate((FieldRef f) => - f.name == 'staticMessage' && - f.declaredType != null && - f.isStatic && - !f.isConst && - !f.isFinal), - ])); - }); + test( + 'Classes', + () async { + var testClass = await service.getObject( + isolate.id, rootLibrary.classes.first.id) as Class; + expect( + testClass.functions, + unorderedEquals([ + predicate((FuncRef f) => f.name == 'staticHello' && f.isStatic), + predicate((FuncRef f) => f.name == 'message' && !f.isStatic), + predicate((FuncRef f) => f.name == 'notFinal' && !f.isStatic), + predicate((FuncRef f) => f.name == 'hello' && !f.isStatic), + predicate((FuncRef f) => f.name == '_equals' && !f.isStatic), + predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic), + predicate((FuncRef f) => f.name == 'toString' && !f.isStatic), + predicate( + (FuncRef f) => f.name == 'noSuchMethod' && !f.isStatic), + predicate( + (FuncRef f) => f.name == 'runtimeType' && !f.isStatic), + ])); + expect( + testClass.fields, + unorderedEquals([ + predicate((FieldRef f) => + f.name == 'message' && + f.declaredType != null && + !f.isStatic && + !f.isConst && + f.isFinal), + predicate((FieldRef f) => + f.name == 'notFinal' && + f.declaredType != null && + !f.isStatic && + !f.isConst && + !f.isFinal), + predicate((FieldRef f) => + f.name == 'staticMessage' && + f.declaredType != null && + f.isStatic && + !f.isConst && + !f.isFinal), + ])); + }, + // TODO(elliette): Remove once 2.15.0 is the stable release. + skip: semver.Version.parse(Platform.version.split(' ').first) >= + semver.Version.parse('2.15.0-268.18.beta') + ? null + : 'SDK does not expose static member information.', + ); test('Runtime classes', () async { var testClass = await service.getObject( From a1ba4e479607cab028ebe508316e1761d86fc95c Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Thu, 2 Dec 2021 12:24:40 -0800 Subject: [PATCH 4/5] Remove skip logic --- dwds/test/chrome_proxy_service_test.dart | 89 +++++++++++------------- 1 file changed, 39 insertions(+), 50 deletions(-) diff --git a/dwds/test/chrome_proxy_service_test.dart b/dwds/test/chrome_proxy_service_test.dart index 72de47a79..5f7311978 100644 --- a/dwds/test/chrome_proxy_service_test.dart +++ b/dwds/test/chrome_proxy_service_test.dart @@ -15,7 +15,6 @@ import 'package:dwds/src/services/chrome_proxy_service.dart'; import 'package:dwds/src/utilities/dart_uri.dart'; import 'package:http/http.dart' as http; import 'package:path/path.dart' as path; -import 'package:pub_semver/pub_semver.dart' as semver; import 'package:test/test.dart'; import 'package:vm_service/vm_service.dart'; import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; @@ -446,55 +445,45 @@ void main() { expect(library1, equals(library2)); }); - test( - 'Classes', - () async { - var testClass = await service.getObject( - isolate.id, rootLibrary.classes.first.id) as Class; - expect( - testClass.functions, - unorderedEquals([ - predicate((FuncRef f) => f.name == 'staticHello' && f.isStatic), - predicate((FuncRef f) => f.name == 'message' && !f.isStatic), - predicate((FuncRef f) => f.name == 'notFinal' && !f.isStatic), - predicate((FuncRef f) => f.name == 'hello' && !f.isStatic), - predicate((FuncRef f) => f.name == '_equals' && !f.isStatic), - predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic), - predicate((FuncRef f) => f.name == 'toString' && !f.isStatic), - predicate( - (FuncRef f) => f.name == 'noSuchMethod' && !f.isStatic), - predicate( - (FuncRef f) => f.name == 'runtimeType' && !f.isStatic), - ])); - expect( - testClass.fields, - unorderedEquals([ - predicate((FieldRef f) => - f.name == 'message' && - f.declaredType != null && - !f.isStatic && - !f.isConst && - f.isFinal), - predicate((FieldRef f) => - f.name == 'notFinal' && - f.declaredType != null && - !f.isStatic && - !f.isConst && - !f.isFinal), - predicate((FieldRef f) => - f.name == 'staticMessage' && - f.declaredType != null && - f.isStatic && - !f.isConst && - !f.isFinal), - ])); - }, - // TODO(elliette): Remove once 2.15.0 is the stable release. - skip: semver.Version.parse(Platform.version.split(' ').first) >= - semver.Version.parse('2.15.0-268.18.beta') - ? null - : 'SDK does not expose static member information.', - ); + test('Classes', () async { + var testClass = await service.getObject( + isolate.id, rootLibrary.classes.first.id) as Class; + expect( + testClass.functions, + unorderedEquals([ + predicate((FuncRef f) => f.name == 'staticHello' && f.isStatic), + predicate((FuncRef f) => f.name == 'message' && !f.isStatic), + predicate((FuncRef f) => f.name == 'notFinal' && !f.isStatic), + predicate((FuncRef f) => f.name == 'hello' && !f.isStatic), + predicate((FuncRef f) => f.name == '_equals' && !f.isStatic), + predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic), + predicate((FuncRef f) => f.name == 'toString' && !f.isStatic), + predicate((FuncRef f) => f.name == 'noSuchMethod' && !f.isStatic), + predicate((FuncRef f) => f.name == 'runtimeType' && !f.isStatic), + ])); + expect( + testClass.fields, + unorderedEquals([ + predicate((FieldRef f) => + f.name == 'message' && + f.declaredType != null && + !f.isStatic && + !f.isConst && + f.isFinal), + predicate((FieldRef f) => + f.name == 'notFinal' && + f.declaredType != null && + !f.isStatic && + !f.isConst && + !f.isFinal), + predicate((FieldRef f) => + f.name == 'staticMessage' && + f.declaredType != null && + f.isStatic && + !f.isConst && + !f.isFinal), + ])); + }); test('Runtime classes', () async { var testClass = await service.getObject( From f3d8bf1a4f863b37cb81034820abd2ab5f61a721 Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Thu, 2 Dec 2021 12:58:07 -0800 Subject: [PATCH 5/5] Update other test case --- dwds/test/chrome_proxy_service_test.dart | 181 +++++++++++++---------- 1 file changed, 104 insertions(+), 77 deletions(-) diff --git a/dwds/test/chrome_proxy_service_test.dart b/dwds/test/chrome_proxy_service_test.dart index 5f7311978..f7be25886 100644 --- a/dwds/test/chrome_proxy_service_test.dart +++ b/dwds/test/chrome_proxy_service_test.dart @@ -15,6 +15,7 @@ import 'package:dwds/src/services/chrome_proxy_service.dart'; import 'package:dwds/src/utilities/dart_uri.dart'; import 'package:http/http.dart' as http; import 'package:path/path.dart' as path; +import 'package:pub_semver/pub_semver.dart' as semver; import 'package:test/test.dart'; import 'package:vm_service/vm_service.dart'; import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; @@ -445,45 +446,55 @@ void main() { expect(library1, equals(library2)); }); - test('Classes', () async { - var testClass = await service.getObject( - isolate.id, rootLibrary.classes.first.id) as Class; - expect( - testClass.functions, - unorderedEquals([ - predicate((FuncRef f) => f.name == 'staticHello' && f.isStatic), - predicate((FuncRef f) => f.name == 'message' && !f.isStatic), - predicate((FuncRef f) => f.name == 'notFinal' && !f.isStatic), - predicate((FuncRef f) => f.name == 'hello' && !f.isStatic), - predicate((FuncRef f) => f.name == '_equals' && !f.isStatic), - predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic), - predicate((FuncRef f) => f.name == 'toString' && !f.isStatic), - predicate((FuncRef f) => f.name == 'noSuchMethod' && !f.isStatic), - predicate((FuncRef f) => f.name == 'runtimeType' && !f.isStatic), - ])); - expect( - testClass.fields, - unorderedEquals([ - predicate((FieldRef f) => - f.name == 'message' && - f.declaredType != null && - !f.isStatic && - !f.isConst && - f.isFinal), - predicate((FieldRef f) => - f.name == 'notFinal' && - f.declaredType != null && - !f.isStatic && - !f.isConst && - !f.isFinal), - predicate((FieldRef f) => - f.name == 'staticMessage' && - f.declaredType != null && - f.isStatic && - !f.isConst && - !f.isFinal), - ])); - }); + test( + 'Classes', + () async { + var testClass = await service.getObject( + isolate.id, rootLibrary.classes.first.id) as Class; + expect( + testClass.functions, + unorderedEquals([ + predicate((FuncRef f) => f.name == 'staticHello' && f.isStatic), + predicate((FuncRef f) => f.name == 'message' && !f.isStatic), + predicate((FuncRef f) => f.name == 'notFinal' && !f.isStatic), + predicate((FuncRef f) => f.name == 'hello' && !f.isStatic), + predicate((FuncRef f) => f.name == '_equals' && !f.isStatic), + predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic), + predicate((FuncRef f) => f.name == 'toString' && !f.isStatic), + predicate( + (FuncRef f) => f.name == 'noSuchMethod' && !f.isStatic), + predicate( + (FuncRef f) => f.name == 'runtimeType' && !f.isStatic), + ])); + expect( + testClass.fields, + unorderedEquals([ + predicate((FieldRef f) => + f.name == 'message' && + f.declaredType != null && + !f.isStatic && + !f.isConst && + f.isFinal), + predicate((FieldRef f) => + f.name == 'notFinal' && + f.declaredType != null && + !f.isStatic && + !f.isConst && + !f.isFinal), + predicate((FieldRef f) => + f.name == 'staticMessage' && + f.declaredType != null && + f.isStatic && + !f.isConst && + !f.isFinal), + ])); + }, + // TODO(elliette): Remove once 2.15.0 is the stable release. + skip: semver.Version.parse(Platform.version.split(' ').first) >= + semver.Version.parse('2.15.0-268.18.beta') + ? null + : 'SDK does not expose static member information.', + ); test('Runtime classes', () async { var testClass = await service.getObject( @@ -708,44 +719,60 @@ void main() { expect(world.offset, 3); }); - test('offset/count parameters are ignored for Classes', () async { - var testClass = await service.getObject( - isolate.id, - rootLibrary.classes.first.id, - offset: 100, - count: 100, - ) as Class; - expect( - testClass.functions, - unorderedEquals([ - predicate((FuncRef f) => f.name == 'message' && !f.isStatic), - predicate((FuncRef f) => f.name == 'notFinal' && !f.isStatic), - predicate((FuncRef f) => f.name == 'hello' && !f.isStatic), - predicate((FuncRef f) => f.name == '_equals' && !f.isStatic), - predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic), - predicate((FuncRef f) => f.name == 'toString' && !f.isStatic), - predicate( - (FuncRef f) => f.name == 'noSuchMethod' && !f.isStatic), - predicate( - (FuncRef f) => f.name == 'runtimeType' && !f.isStatic), - ])); - expect( - testClass.fields, - unorderedEquals([ - predicate((FieldRef f) => - f.name == 'message' && - f.declaredType != null && - !f.isStatic && - !f.isConst && - f.isFinal), - predicate((FieldRef f) => - f.name == 'notFinal' && - f.declaredType != null && - !f.isStatic && - !f.isConst && - !f.isFinal), - ])); - }); + test( + 'offset/count parameters are ignored for Classes', + () async { + var testClass = await service.getObject( + isolate.id, + rootLibrary.classes.first.id, + offset: 100, + count: 100, + ) as Class; + expect( + testClass.functions, + unorderedEquals([ + predicate( + (FuncRef f) => f.name == 'staticHello' && f.isStatic), + predicate((FuncRef f) => f.name == 'message' && !f.isStatic), + predicate((FuncRef f) => f.name == 'notFinal' && !f.isStatic), + predicate((FuncRef f) => f.name == 'hello' && !f.isStatic), + predicate((FuncRef f) => f.name == '_equals' && !f.isStatic), + predicate((FuncRef f) => f.name == 'hashCode' && !f.isStatic), + predicate((FuncRef f) => f.name == 'toString' && !f.isStatic), + predicate( + (FuncRef f) => f.name == 'noSuchMethod' && !f.isStatic), + predicate( + (FuncRef f) => f.name == 'runtimeType' && !f.isStatic), + ])); + expect( + testClass.fields, + unorderedEquals([ + predicate((FieldRef f) => + f.name == 'message' && + f.declaredType != null && + !f.isStatic && + !f.isConst && + f.isFinal), + predicate((FieldRef f) => + f.name == 'notFinal' && + f.declaredType != null && + !f.isStatic && + !f.isConst && + !f.isFinal), + predicate((FieldRef f) => + f.name == 'staticMessage' && + f.declaredType != null && + f.isStatic && + !f.isConst && + !f.isFinal), + ])); + }, + // TODO(elliette): Remove once 2.15.0 is the stable release. + skip: semver.Version.parse(Platform.version.split(' ').first) >= + semver.Version.parse('2.15.0-268.18.beta') + ? null + : 'SDK does not expose static member information.', + ); test('offset/count parameters are ignored for bools', () async { var ref = await service.evaluate(