@@ -60,6 +60,18 @@ class DevtoolsFormatCommand extends Command<void> with PrintUsageException {
6060 output['n' ] = '' ;
6161 output['type' ] = "web" ;
6262
63+ /// Adds "isDeferred" flag to each child of a treeMap using a helper stack.
64+ void addDeferredFlag (Map <String , dynamic > treeMap, bool flag) {
65+ List <dynamic > stack = [];
66+ treeMap['isDeferred' ] = flag;
67+ stack.add (treeMap);
68+ while (stack.isNotEmpty) {
69+ var item = stack.removeLast ();
70+ item['isDeferred' ] = flag;
71+ stack.addAll (item['children' ] ?? []);
72+ }
73+ }
74+
6375 if (outputUnits.length == 1 ) {
6476 vm.ProgramInfo programInfoTree =
6577 builder.build (allInfo, outputUnits.keys.first);
@@ -77,34 +89,18 @@ class DevtoolsFormatCommand extends Command<void> with PrintUsageException {
7789 treeMap['n' ] = treemapRoots[outputUnitName];
7890 if (treeMap['n' ] == 'main' ) {
7991 mainOutput.addAll (treeMap);
80- treeMap['isDeferred' ] = false ;
81- // recursively visit children
82- List <dynamic > mainStack = [];
83- mainStack.add (treeMap);
84- while (mainStack.isNotEmpty) {
85- var item = mainStack.removeLast ();
86- item['isDeferred' ] = false ;
87- mainStack.addAll (item['children' ] ?? []);
88- }
92+ // Recursively tag each child in treeMap with "isDeferred" flag
93+ addDeferredFlag (treeMap, false );
8994 } else {
9095 Map <String , dynamic > deferredOutput = {};
9196 deferredOutput.addAll (treeMap);
92- treeMap['isDeferred' ] = true ;
93- List <dynamic > deferredStack = [];
94- deferredStack.add (treeMap);
95- while (deferredStack.isNotEmpty) {
96- var item = deferredStack.removeLast ();
97- item['isDeferred' ] = true ;
98- deferredStack.addAll (item['children' ] ?? []);
99- }
97+ addDeferredFlag (treeMap, true );
10098 deferredOutputs.add (deferredOutput);
10199 }
102100 treeMap['value' ] = treemapSizes[outputUnitName];
103101 }
104102 output['children' ].add (mainOutput);
105- for (var deferredUnit in deferredOutputs) {
106- output['children' ].add (deferredUnit);
107- }
103+ output['children' ].addAll (deferredOutputs);
108104 }
109105 if (outputPath == null ) {
110106 print (jsonEncode (output));
@@ -119,7 +115,7 @@ class DevtoolsFormatCommand extends Command<void> with PrintUsageException {
119115/// The [vm.ProgramInfoNode] tree has a similar structure to the [AllInfo] tree
120116/// except that the root has packages, libraries, constants, and typedefs as
121117/// immediate children.
122- class ProgramInfoBuilder extends VMProgramInfoVisitor <vm.ProgramInfoNode > {
118+ class ProgramInfoBuilder extends VMProgramInfoVisitor <vm.ProgramInfoNode ? > {
123119 final AllInfo info;
124120
125121 final program = vm.ProgramInfo ();
@@ -141,9 +137,12 @@ class ProgramInfoBuilder extends VMProgramInfoVisitor<vm.ProgramInfoNode> {
141137 String compositeName (String name, String outputUnitName) =>
142138 "$name /$outputUnitName " ;
143139
140+ /// Mapping between the name of an OutputUnitInfo and the OutputUnitInfo object.
141+ Map <String , OutputUnitInfo > outputUnitInfos = {};
142+
144143 /// Mapping between the composite name of a package and the corresponding
145- /// [vm.ProgramInfoNode ] objects of [vm.NodeType.packageNode] .
146- final Map <String , dynamic > packageInfoNodes = {};
144+ /// [PackageInfo ] objects.
145+ final Map <String , PackageInfo > packageInfos = {};
147146
148147 /// Mapping between an <unnamed> [LibraryInfo] object and the name of the
149148 /// corresponding [vm.ProgramInfoNode] object.
@@ -159,25 +158,42 @@ class ProgramInfoBuilder extends VMProgramInfoVisitor<vm.ProgramInfoNode> {
159158 libraryName = longName (libraryInfo, useLibraryUri: true , forId: true );
160159 }
161160 String packageName = libraryGroupName (libraryInfo) ?? libraryName;
162- vm.ProgramInfoNode ? packageInfoNode = packageInfoNodes[packageName];
161+ String compositePackageName = compositeName (packageName, outputUnitName);
162+ vm.ProgramInfoNode ? packageInfoNode = infoNodesByName[compositePackageName];
163163 if (packageInfoNode == null ) {
164- String compositePackageName = compositeName (packageName, outputUnitName);
165164 vm.ProgramInfoNode newPackage = outputUnit.makeNode (
166- name: compositePackageName ,
165+ name: packageName ,
167166 parent: outputUnit.root,
168167 type: vm.NodeType .packageNode);
169- newPackage.size = libraryInfo.size;
170- packageInfoNodes[compositePackageName] = newPackage;
168+ newPackage.size = 0 ;
171169 outputUnit.root.children[compositePackageName] = newPackage;
172170 var packageNode = infoNodesByName[compositePackageName];
173171 assert (packageNode == null ,
174172 "encountered package with duplicated name: $compositePackageName " );
175173 infoNodesByName[compositePackageName] = newPackage;
176- } else {
177- packageInfoNode.size = (packageInfoNode.size ?? 0 ) + libraryInfo.size;
174+
175+ /// Add the corresponding [PackageInfo] node in the [AllInfo] tree.
176+ OutputUnitInfo packageUnit = outputUnitInfos[outputUnitName]! ;
177+ PackageInfo newPackageInfo =
178+ PackageInfo (packageName, packageUnit, newPackage.size! );
179+ newPackageInfo.libraries.add (libraryInfo);
180+ info.packages.add (newPackageInfo);
178181 }
179182 }
180183
184+ /// Aggregates the size of a library [vm.ProgramInfoNode] from the sizes of
185+ /// its top level children in the same output unit.
186+ int collectSizesForOutputUnit (
187+ Iterable <BasicInfo > infos, String outputUnitName) {
188+ int sizes = 0 ;
189+ for (var info in infos) {
190+ if (info.outputUnit! .filename == outputUnitName) {
191+ sizes += info.size;
192+ }
193+ }
194+ return sizes;
195+ }
196+
181197 void makeLibrary (LibraryInfo libraryInfo, String outputUnitName) {
182198 vm.ProgramInfo outputUnit = outputUnits[outputUnitName]! ;
183199 String libraryName = libraryInfo.name;
@@ -190,11 +206,18 @@ class ProgramInfoBuilder extends VMProgramInfoVisitor<vm.ProgramInfoNode> {
190206 vm.ProgramInfoNode parentNode = infoNodesByName[compositePackageName]! ;
191207 String compositeLibraryName = compositeName (libraryName, outputUnitName);
192208 vm.ProgramInfoNode newLibrary = outputUnit.makeNode (
193- name: compositeLibraryName,
194- parent: parentNode,
195- type: vm.NodeType .libraryNode);
196- newLibrary.size = libraryInfo.size;
209+ name: libraryName, parent: parentNode, type: vm.NodeType .libraryNode);
210+ newLibrary.size = 0 ;
211+ newLibrary.size = (newLibrary.size ?? 0 ) +
212+ collectSizesForOutputUnit (
213+ libraryInfo.topLevelFunctions, outputUnitName) +
214+ collectSizesForOutputUnit (
215+ libraryInfo.topLevelVariables, outputUnitName) +
216+ collectSizesForOutputUnit (libraryInfo.classes, outputUnitName) +
217+ collectSizesForOutputUnit (libraryInfo.classTypes, outputUnitName) +
218+ collectSizesForOutputUnit (libraryInfo.typedefs, outputUnitName);
197219 parentNode.children[newLibrary.name] = newLibrary;
220+ parentNode.size = (parentNode.size ?? 0 ) + newLibrary.size! ;
198221 vm.ProgramInfoNode ? libraryNode = infoNodesByName[compositeLibraryName];
199222 assert (libraryNode == null ,
200223 "encountered library with duplicated name: $compositeLibraryName " );
@@ -268,7 +291,7 @@ class ProgramInfoBuilder extends VMProgramInfoVisitor<vm.ProgramInfoNode> {
268291 ///
269292 /// Note: we might want to create a separate [vm.NodeType.fieldNode] to
270293 /// differentiate fields from other miscellaneous nodes for constructing
271- /// the call graph.
294+ /// the call graph in the future .
272295 void makeField (FieldInfo fieldInfo) {
273296 Info ? parent = fieldInfo.parent;
274297 String outputUnitName = fieldInfo.outputUnit! .filename;
@@ -387,6 +410,7 @@ class ProgramInfoBuilder extends VMProgramInfoVisitor<vm.ProgramInfoNode> {
387410 @override
388411 vm.ProgramInfoNode visitOutput (OutputUnitInfo info) {
389412 vm.ProgramInfo ? outputUnit = outputUnits[info.filename];
413+ outputUnitInfos[info.filename] = info;
390414 assert (outputUnit == null , "encountered outputUnit with duplicated name" );
391415 var newUnit = vm.ProgramInfo ();
392416 outputUnits[info.filename] = newUnit;
@@ -399,9 +423,6 @@ class ProgramInfoBuilder extends VMProgramInfoVisitor<vm.ProgramInfoNode> {
399423 for (var package in info.packages) {
400424 visitPackage (package, outputUnitName);
401425 }
402- for (var library in info.libraries) {
403- visitLibrary (library, outputUnitName);
404- }
405426 info.constants.forEach (makeConstant);
406427 info.constants.forEach (visitConstant);
407428 return outputUnits[outputUnitName]! .root;
@@ -422,7 +443,7 @@ class ProgramInfoBuilder extends VMProgramInfoVisitor<vm.ProgramInfoNode> {
422443 }
423444
424445 @override
425- vm.ProgramInfoNode visitLibrary (LibraryInfo info, String outputUnitName) {
446+ vm.ProgramInfoNode ? visitLibrary (LibraryInfo info, String outputUnitName) {
426447 info.topLevelFunctions.forEach (makeFunction);
427448 info.topLevelFunctions.forEach (visitFunction);
428449 info.topLevelVariables.forEach (makeField);
@@ -433,9 +454,11 @@ class ProgramInfoBuilder extends VMProgramInfoVisitor<vm.ProgramInfoNode> {
433454 info.classTypes.forEach (visitClassType);
434455 info.typedefs.forEach (makeTypedef);
435456 info.typedefs.forEach (visitTypedef);
436- return infoNodesByName[compositeName (info.name, outputUnitName)] ??
437- infoNodesByName[
438- compositeName (unnamedLibraries[info]! , outputUnitName)]! ;
457+ vm.ProgramInfoNode currentLibrary =
458+ infoNodesByName[compositeName (info.name, outputUnitName)] ??
459+ infoNodesByName[
460+ compositeName (unnamedLibraries[info]! , outputUnitName)]! ;
461+ return currentLibrary;
439462 }
440463
441464 @override
0 commit comments