86ccb1fb6e
Change-Id: I5c9857090eed7bf521ba581d0c9051606ed45304 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/205940 Auto-Submit: Bob Nystrom <rnystrom@google.com> Commit-Queue: Bob Nystrom <rnystrom@google.com> Reviewed-by: Phil Quitslund <pquitslund@google.com>
165 lines
4.6 KiB
Dart
165 lines
4.6 KiB
Dart
// Copyright (c) 2020, 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' as math;
|
|
|
|
import 'package:analyzer/dart/ast/ast.dart';
|
|
import 'package:analyzer/dart/ast/token.dart';
|
|
|
|
import 'package:scrape/scrape.dart';
|
|
|
|
/// The paths to each build() method and its maximum nesting level.
|
|
final buildMethods = <String, int>{};
|
|
|
|
bool simplifyNames = false;
|
|
|
|
void main(List<String> arguments) {
|
|
arguments = arguments.toList();
|
|
simplifyNames = arguments.remove('--simplify');
|
|
var allCode = arguments.remove('--all');
|
|
|
|
Scrape()
|
|
// The number of levels of nesting active when each argument appears.
|
|
..addHistogram('Nesting depth')
|
|
// The number of levels of nesting active when each argument appears without
|
|
// counting lists.
|
|
..addHistogram('Ignoring lists')
|
|
// The number of levels of "child" or "children" named parameter nesting
|
|
// when each argument appears.
|
|
..addHistogram('Child nesting depth')
|
|
..addHistogram('Argument names')
|
|
// Strings that describe the structure of each nested argument.
|
|
..addHistogram('Argument nesting')
|
|
..addVisitor(() => NestingVisitor(allCode: allCode))
|
|
..runCommandLine(arguments);
|
|
|
|
var methods = buildMethods.keys.toList();
|
|
methods.sort((a, b) => buildMethods[b]!.compareTo(buildMethods[a]!));
|
|
for (var method in methods) {
|
|
print('${buildMethods[method].toString().padLeft(3)}: $method');
|
|
}
|
|
print('${buildMethods.length} build() methods');
|
|
}
|
|
|
|
class NestingVisitor extends ScrapeVisitor {
|
|
final List<String> _stack = [];
|
|
|
|
final bool _allCode;
|
|
bool _pushed = false;
|
|
int _deepestNesting = 0;
|
|
|
|
NestingVisitor({bool? allCode}) : _allCode = allCode ?? false;
|
|
|
|
@override
|
|
void beforeVisitBuildMethod(Declaration node) {
|
|
_deepestNesting = 0;
|
|
}
|
|
|
|
@override
|
|
void afterVisitBuildMethod(Declaration node) {
|
|
var startLine = lineInfo.getLocation(node.offset).lineNumber;
|
|
buildMethods['$path:$startLine'] = _deepestNesting;
|
|
}
|
|
|
|
@override
|
|
void visitArgumentList(ArgumentList node) {
|
|
// Only argument lists with trailing commas get indentation.
|
|
if (node.arguments.isNotEmpty &&
|
|
node.arguments.last.endToken.next!.type == TokenType.COMMA) {
|
|
String name;
|
|
var parent = node.parent;
|
|
if (parent is MethodInvocation) {
|
|
name = parent.methodName.name;
|
|
} else if (parent is InstanceCreationExpression) {
|
|
name = parent.constructorName.toString();
|
|
} else if (parent is SuperConstructorInvocation) {
|
|
name = 'super.${parent.constructorName}';
|
|
} else {
|
|
name = '?(${parent.runtimeType})?';
|
|
}
|
|
|
|
if (simplifyNames) {
|
|
name = '';
|
|
}
|
|
|
|
for (var argument in node.arguments) {
|
|
var argName =
|
|
argument is NamedExpression ? argument.name.label.name : '';
|
|
|
|
if (_allCode || isInFlutterBuildMethod) {
|
|
record('Argument names', argName);
|
|
}
|
|
|
|
if (simplifyNames && argName != 'child' && argName != 'children') {
|
|
argName = '_';
|
|
}
|
|
|
|
_push('$name($argName:');
|
|
argument.accept(this);
|
|
_pop();
|
|
}
|
|
} else {
|
|
node.visitChildren(this);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void visitBlock(Block node) {
|
|
var isFunction = node.parent is BlockFunctionBody;
|
|
if (!isFunction) _push('{');
|
|
node.visitChildren(this);
|
|
if (!isFunction) _pop();
|
|
}
|
|
|
|
@override
|
|
void visitExpressionFunctionBody(ExpressionFunctionBody node) {
|
|
_push('=>');
|
|
node.visitChildren(this);
|
|
_pop();
|
|
}
|
|
|
|
@override
|
|
void visitFunctionExpression(FunctionExpression node) {
|
|
var isDeclaration = node.parent is FunctionDeclaration;
|
|
if (!isDeclaration) _push('(){');
|
|
node.visitChildren(this);
|
|
if (!isDeclaration) _pop();
|
|
}
|
|
|
|
@override
|
|
void visitListLiteral(ListLiteral node) {
|
|
for (var element in node.elements) {
|
|
_push('[');
|
|
element.accept(this);
|
|
_pop();
|
|
}
|
|
}
|
|
|
|
@override
|
|
void visitSetOrMapLiteral(SetOrMapLiteral node) {
|
|
for (var element in node.elements) {
|
|
_push('{');
|
|
element.accept(this);
|
|
_pop();
|
|
}
|
|
}
|
|
|
|
void _push(String string) {
|
|
_stack.add(string);
|
|
_pushed = true;
|
|
_deepestNesting = math.max(_deepestNesting, _stack.length);
|
|
}
|
|
|
|
void _pop() {
|
|
if (_pushed && (_allCode || isInFlutterBuildMethod)) {
|
|
record('Argument nesting', _stack.join(' '));
|
|
record('Nesting depth', _stack.length);
|
|
record('Ignoring lists', _stack.where((s) => s != '[').length);
|
|
record('Child nesting depth',
|
|
_stack.where((s) => s.contains('child')).length);
|
|
}
|
|
_pushed = false;
|
|
_stack.removeLast();
|
|
}
|
|
}
|