Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

extend const_finder to allow skipping particular classes #37257

Merged
merged 13 commits into from
Nov 11, 2022
Merged
3 changes: 2 additions & 1 deletion testing/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,8 @@ def GatherConstFinderTests(build_dir):
'--disable-dart-dev',
os.path.join(test_dir, 'const_finder_test.dart'),
os.path.join(build_dir, 'gen', 'frontend_server.dart.snapshot'),
os.path.join(build_dir, 'flutter_patched_sdk')
os.path.join(build_dir, 'flutter_patched_sdk'),
os.path.join(build_dir, 'dart-sdk', 'lib', 'libraries.json')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This path is needed to do web compilation

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should pass a Flutter-specific flutter/web_sdk/libraries.json file instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right, I double checked what we do in the tool, and it's actually that file, will update

Copy link
Contributor Author

@christopherfujino christopherfujino Nov 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, using that file does not work in this test as for dart2js it just points to a relative path to the dart-sdk libraries.json https://github.com/flutter/engine/blob/main/web_sdk/libraries.json#L26. This path ("../dart-sdk/lib/libraries.json") is relative to its position in the Flutter cache, however, not the engine workspace.

Passing the dart-sdk version directly should be functionally equivalent however.

]
yield EngineExecutableTask(
build_dir,
Expand Down
31 changes: 28 additions & 3 deletions tools/const_finder/bin/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,47 @@ void main(List<String> args) {
..addOption('kernel-file',
valueHelp: 'path/to/main.dill',
help: 'The path to a kernel file to parse, which was created from the '
'main-package-uri library.')
'main-package-uri library.',
mandatory: true)
..addOption('class-library-uri',
mandatory: true,
help: 'The package: URI of the class to find.',
valueHelp: 'package:flutter/src/widgets/icon_data.dart')
..addOption('class-name',
help: 'The class name for the class to find.', valueHelp: 'IconData')
help: 'The class name for the class to find.',
valueHelp: 'IconData',
mandatory: true)
..addSeparator('Optional arguments:')
..addFlag('pretty',
negatable: false,
help: 'Pretty print JSON output (defaults to false).')
..addFlag('help',
abbr: 'h',
negatable: false,
help: 'Print usage and exit');
help: 'Print usage and exit')
..addOption('annotation-class-name',
help: 'The class name of the annotation for classes that should be '
'ignored.',
valueHelp: 'StaticIconProvider')
..addOption('annotation-class-library-uri',
help: 'The package: URI of the class of the annotation for classes '
'that should be ignored.',
valueHelp: 'package:flutter/src/material/icons.dart');

final ArgResults argResults = parser.parse(args);
T getArg<T>(String name) => argResults[name] as T;

final String? annotationClassName = getArg<String?>('annotation-class-name');
final String? annotationClassLibraryUri = getArg<String?>('annotation-class-library-uri');

final bool annotationClassNameProvided = annotationClassName != null;
final bool annotationClassLibraryUriProvided = annotationClassLibraryUri != null;
if (annotationClassNameProvided != annotationClassLibraryUriProvided) {
throw StateError(
'If either "--annotation-class-name" or "--annotation-class-library-uri" are provided they both must be',
);
}

if (getArg<bool>('help')) {
stdout.writeln(parser.usage);
exit(0);
Expand All @@ -69,6 +92,8 @@ void main(List<String> args) {
kernelFilePath: getArg<String>('kernel-file'),
classLibraryUri: getArg<String>('class-library-uri'),
className: getArg<String>('class-name'),
annotationClassName: annotationClassName,
annotationClassLibraryUri: annotationClassLibraryUri,
);

final JsonEncoder encoder = getArg<bool>('pretty')
Expand Down
45 changes: 44 additions & 1 deletion tools/const_finder/lib/const_finder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class _ConstVisitor extends RecursiveVisitor<void> {
this.kernelFilePath,
this.classLibraryUri,
this.className,
this.annotationClassLibraryUri,
this.annotationClassName,
) : _visitedInstances = <String>{},
constantInstances = <Map<String, dynamic>>[],
nonConstantLocations = <Map<String, dynamic>>[];
Expand All @@ -28,6 +30,16 @@ class _ConstVisitor extends RecursiveVisitor<void> {
final List<Map<String, dynamic>> constantInstances;
final List<Map<String, dynamic>> nonConstantLocations;

bool inIgnoredClass = false;

/// The name of the name of the class of the annotation marking classes
/// whose constant references should be ignored.
final String? annotationClassName;

/// The library URI of the class of the annotation marking classes whose
/// constant references should be ignored.
final String? annotationClassLibraryUri;

// A cache of previously evaluated classes.
static final Map<Class, bool> _classHeirarchyCache = <Class, bool>{};
bool _matches(Class node) {
Expand Down Expand Up @@ -72,12 +84,39 @@ class _ConstVisitor extends RecursiveVisitor<void> {
super.visitConstructorInvocation(node);
}

@override
void visitClass(Class node) {
// check if this is a class that we should ignore
inIgnoredClass = _classShouldBeIgnored(node);
super.visitClass(node);
inIgnoredClass = false;
}

// If any annotations on the class match annotationClassName AND
// annotationClassLibraryUri.
bool _classShouldBeIgnored(Class node) {
if (annotationClassName == null || annotationClassLibraryUri == null) {
return false;
}
return node.annotations.any((Expression expression) {
if (expression is! ConstantExpression) {
return false;
}

final Constant constant = expression.constant;
return constant is InstanceConstant
&& constant.classNode.name == annotationClassName
&& constant.classNode.enclosingLibrary.importUri.toString() == annotationClassLibraryUri;
});
}

@override
void visitInstanceConstantReference(InstanceConstant node) {
super.visitInstanceConstantReference(node);
if (!_matches(node.classNode)) {
if (!_matches(node.classNode) || inIgnoredClass) {
return;
}

final Map<String, dynamic> instance = <String, dynamic>{};
for (final MapEntry<Reference, Constant> kvp in node.fieldValues.entries) {
if (kvp.value is! PrimitiveConstant<dynamic>) {
Expand All @@ -102,10 +141,14 @@ class ConstFinder {
required String kernelFilePath,
required String classLibraryUri,
required String className,
String? annotationClassLibraryUri,
String? annotationClassName,
}) : _visitor = _ConstVisitor(
kernelFilePath,
classLibraryUri,
className,
annotationClassLibraryUri,
annotationClassName,
);

final _ConstVisitor _visitor;
Expand Down
2 changes: 1 addition & 1 deletion tools/const_finder/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ name: const_finder
publish_to: none

environment:
sdk: ">=2.12.0 <3.0.0"
sdk: ">=2.17.0 <3.0.0"

# Do not add any dependencies that require more than what is provided in
# //third_party/dart/pkg or //third_party/dart/third_party/pkg.
Expand Down
Loading