Skip to content

Commit 0f04dc6

Browse files
gmc-googlecommit-bot@chromium.org
authored andcommitted
Added checks to gather method data
Change-Id: I809e05ea3554ae9768d3f9cb25c824bbe36ca2bb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/203600 Commit-Queue: Gabriel Castro <[email protected]> Reviewed-by: Nicholas Shahan <[email protected]> Reviewed-by: Srujan Gaddam <[email protected]>
1 parent 53198d4 commit 0f04dc6

File tree

3 files changed

+122
-19
lines changed

3 files changed

+122
-19
lines changed

pkg/compiler/tool/kernel_visitor/dart_html_metrics_visitor.dart

Lines changed: 98 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
4+
import "dart:convert";
45
import "dart:io";
56
import "package:kernel/kernel.dart";
67
import "package:kernel/ast.dart";
78

8-
main(List<String> args) {
9+
main(List<String> args) async {
910
// Ensure right args are passed.
1011
if (args.length < 1) {
1112
print("usage: ${Platform.script} a.dill");
@@ -19,8 +20,8 @@ main(List<String> args) {
1920
// Visit component.
2021
component.accept(visitor);
2122

22-
// Print compiled data.
23-
print(visitor.classInfo);
23+
// Save data to file.
24+
visitor.saveDataToFile("dart2html_metrics.json");
2425
}
2526

2627
/// Visits classes in libraries specified by `libraryFilter`
@@ -55,12 +56,13 @@ class MetricsVisitor extends RecursiveVisitor {
5556

5657
@override
5758
void visitProcedure(Procedure node) {
58-
// If this method invokes super, track for class.
59-
if (node.containsSuperCalls) {
60-
classInfo[currentClass]
61-
.methods
62-
.add(ClassMetricsMethod(node.name.text, true));
63-
}
59+
classInfo[currentClass].methods.add(ClassMetricsMethod(
60+
node.name.text,
61+
node.containsSuperCalls,
62+
node.isInstanceMember,
63+
node.isExternal,
64+
node.isAbstract,
65+
node.kind.toString()));
6466
}
6567

6668
@override
@@ -71,6 +73,11 @@ class MetricsVisitor extends RecursiveVisitor {
7173
currentClass = node.name;
7274
var metrics = ClassMetrics();
7375

76+
// Check if class contains native members.
77+
if (node.annotations.any(_isNativeMarkerAnnotation)) {
78+
metrics.containsNativeMember = true;
79+
}
80+
7481
// Check if Mixed.
7582
if (node.superclass?.isAnonymousMixin ?? false) {
7683
metrics.mixed = true;
@@ -83,18 +90,26 @@ class MetricsVisitor extends RecursiveVisitor {
8390
metrics.parent = unmangledParent;
8491
}
8592

93+
// Check for implemented classes.
94+
if (node.implementedTypes.length > 0) {
95+
var implementedTypes =
96+
node.implementedTypes.map((type) => type.className.asClass.name);
97+
metrics.implementedTypes = implementedTypes.toList();
98+
}
99+
86100
classInfo[currentClass] = metrics;
101+
87102
super.visitClass(node);
88103
}
89104
}
90105

91106
// Returns List of parsed mixins from superclass name.
92107
List<String> _filterMixins(String superWithMixins) {
93-
var start = superWithMixins.indexOf('with') + 4;
108+
var start = superWithMixins.indexOf("with") + 4;
94109
var mixins = superWithMixins.substring(start);
95-
mixins = mixins.replaceAll(' ', '');
110+
mixins = mixins.replaceAll(" ", "");
96111

97-
return mixins.split(',');
112+
return mixins.split(",");
98113
}
99114

100115
// Recursively searches superclasses, filtering anonymous mixins,
@@ -107,31 +122,76 @@ class MetricsVisitor extends RecursiveVisitor {
107122
return node.name;
108123
}
109124

110-
// Passes through the aggregated data and does post processing,
111-
// adding classes that inherit.
125+
// Returns true if a class Annotation is Native.
126+
bool _isNativeMarkerAnnotation(Expression annotation) {
127+
if (annotation is ConstructorInvocation) {
128+
var type = annotation.constructedType;
129+
if (type.classNode.name == "Native") {
130+
return true;
131+
}
132+
}
133+
return false;
134+
}
135+
136+
// Passes through the aggregated data and processes,
137+
// adding child classes and overridden methods from parent.
112138
void _processData() {
113139
classInfo.keys.forEach((className) {
114140
var parentName = classInfo[className].parent;
115-
116141
if (classInfo[parentName] != null) {
117142
classInfo[parentName].inheritedBy.add(className);
143+
144+
var notOverridden = <String>[];
145+
var parentMethods = classInfo[parentName].methods.map((m) => m.name);
146+
var classMethods = classInfo[className].methods.map((m) => m.name);
147+
148+
parentMethods.forEach((method) =>
149+
{if (!classMethods.contains(method)) notOverridden.add(method)});
150+
151+
// Update Method Info.
152+
classInfo[className].notOverriddenMethods = notOverridden;
118153
}
119154
});
120155
}
156+
157+
// Saves the data to file.
158+
void saveDataToFile(String filename) {
159+
var formatted = jsonFormat(classInfo);
160+
161+
File(filename).writeAsStringSync(formatted);
162+
}
163+
164+
// Converts the passed Map to a pretty print JSON string.
165+
String jsonFormat(Map<String, ClassMetrics> info) {
166+
JsonEncoder encoder = new JsonEncoder.withIndent(" ");
167+
return encoder.convert(info);
168+
}
121169
}
122170

123171
/// Tracks info compiled for a class.
124172
class ClassMetrics {
125173
List<ClassMetricsMethod> methods;
126174
List<String> mixins;
175+
List<String> implementedTypes;
176+
List<String> notOverriddenMethods;
127177
List<String> inheritedBy;
128178
String parent;
129179
bool mixed;
180+
bool containsNativeMember;
130181

131182
ClassMetrics(
132-
{this.parent, this.mixed = false, mixins, methods, inheritedBy}) {
133-
this.mixins = mixins ?? [];
183+
{this.mixed = false,
184+
this.containsNativeMember = false,
185+
this.parent,
186+
methods,
187+
mixins,
188+
notOverridden,
189+
implementedTypes,
190+
inheritedBy}) {
134191
this.methods = methods ?? [];
192+
this.mixins = mixins ?? [];
193+
this.notOverriddenMethods = notOverridden ?? [];
194+
this.implementedTypes = implementedTypes ?? [];
135195
this.inheritedBy = inheritedBy ?? [];
136196
}
137197

@@ -151,18 +211,37 @@ class ClassMetrics {
151211
"mixins": mixins,
152212
"parent": parent,
153213
"inheritedBy": inheritedBy,
214+
"containsNativeMember": containsNativeMember,
215+
"notOverriddenMethods": notOverriddenMethods,
216+
"implementedTypes": implementedTypes
154217
};
155218
}
156219
}
157220

158221
/// Tracks info related to a specific method.
159222
class ClassMetricsMethod {
160223
String name;
224+
String methodKind;
161225
bool invokesSuper;
226+
bool isInstanceMember;
227+
bool isExternal;
228+
bool isAbstract;
162229

163-
ClassMetricsMethod(this.name, [this.invokesSuper = false]);
230+
ClassMetricsMethod(this.name,
231+
[this.invokesSuper = false,
232+
this.isInstanceMember = false,
233+
this.isExternal = false,
234+
this.isAbstract = false,
235+
this.methodKind = ""]);
164236

165237
Map<String, dynamic> toJson() {
166-
return {"name": name, "invokesSuper": invokesSuper};
238+
return {
239+
"name": name,
240+
"invokesSuper": invokesSuper,
241+
"isInstanceMember": isInstanceMember,
242+
"isExternal": isExternal,
243+
"isAbstract": isAbstract,
244+
"methodKind": methodKind
245+
};
167246
}
168247
}

pkg/compiler/tool/kernel_visitor/test/info_visitor_test.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,13 @@ main() async {
8484
Expect.equals(visitor.classInfo["F"].mixed, true);
8585
Expect.deepEquals(visitor.classInfo["F"].mixins, ["Mix1", "Mix2"]);
8686
});
87+
88+
test("Class E implements A", () {
89+
Expect.equals(visitor.classInfo["E"].implementedTypes.contains("A"), true);
90+
});
91+
92+
test("Class G extends A but fails to override getValue()", () {
93+
Expect.equals(
94+
visitor.classInfo["G"].notOverriddenMethods.contains("getValue"), true);
95+
});
8796
}

pkg/compiler/tool/kernel_visitor/test/test_classes.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,18 @@ class D with Mix1, Mix2 {
4343
class F extends B with Mix1, Mix2 {
4444
F();
4545
}
46+
47+
// Test class with interface
48+
class E implements A {
49+
E();
50+
51+
@override
52+
getValue() {
53+
return "E Value";
54+
}
55+
}
56+
57+
// Test class with unoverriden superclass method
58+
class G extends A {
59+
G();
60+
}

0 commit comments

Comments
 (0)