diff --git a/tools/const_finder/BUILD.gn b/tools/const_finder/BUILD.gn index c20766d7d8643..d628749c26fca 100644 --- a/tools/const_finder/BUILD.gn +++ b/tools/const_finder/BUILD.gn @@ -13,7 +13,6 @@ application_snapshot("const_finder") { inputs = [ "bin/main.dart", - "lib/const_finder.dart", ".dart_tool/package_config.json", ] diff --git a/tools/const_finder/bin/main.dart b/tools/const_finder/bin/main.dart index d20423687ed4d..0a64dc452f8b6 100644 --- a/tools/const_finder/bin/main.dart +++ b/tools/const_finder/bin/main.dart @@ -6,7 +6,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:args/args.dart'; -import 'package:const_finder/const_finder.dart'; +import 'package:kernel/const_finder.dart'; void main(List args) { final ArgParser parser = ArgParser(); diff --git a/tools/const_finder/lib/const_finder.dart b/tools/const_finder/lib/const_finder.dart deleted file mode 100644 index 84f9c809b2f1e..0000000000000 --- a/tools/const_finder/lib/const_finder.dart +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2013 The Flutter Authors. 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:collection'; - -import 'package:kernel/kernel.dart'; - -class _ConstVisitor extends RecursiveVisitor { - _ConstVisitor( - this.kernelFilePath, - this.classLibraryUri, - this.className, - this.annotationClassLibraryUri, - this.annotationClassName, - ) : _visitedInstances = {}, - constantInstances = >[], - nonConstantLocations = >[]; - - /// The path to the file to open. - final String kernelFilePath; - - /// The library URI for the class to find. - final String classLibraryUri; - - /// The name of the class to find. - final String className; - - final Set _visitedInstances; - final List> constantInstances; - final List> nonConstantLocations; - - bool inIgnoredClass = false; - - /// Whether or not we are currently within the declaration of the target class. - /// - /// We use this to determine when to skip tracking non-constant - /// [ConstructorInvocation]s. This is because, in web builds, a static - /// method is always created called _#new#tearOff() which returns the result - /// of a non-constant invocation of the unnamed constructor. - /// - /// For the following Dart class "FooBar": - /// - /// class FooBar { - /// const FooBar(); - /// } - /// - /// The following kernel structure is generated: - /// - /// class FooBar extends core::Object /*hasConstConstructor*/ { - /// const constructor •() → min::FooBar - /// : super core::Object::•() - /// ; - /// static method _#new#tearOff() → min::FooBar - /// return new min::FooBar::•(); /* this is a non-const constructor invocation */ - /// method noOp() → void {} - /// } - bool inTargetClass = false; - - bool inTargetTearOff = 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 _classHeirarchyCache = {}; - bool _matches(Class node) { - final bool? result = _classHeirarchyCache[node]; - if (result != null) { - return result; - } - final bool exactMatch = node.name == className - && node.enclosingLibrary.importUri.toString() == classLibraryUri; - final bool match = exactMatch - || node.supers.any((Supertype supertype) => _matches(supertype.classNode)); - _classHeirarchyCache[node] = match; - return match; - } - - // Avoid visiting the same constant more than once. - final Set _cache = LinkedHashSet.identity(); - - @override - void visitProcedure(Procedure node) { - final bool isTearOff = node.isStatic && - node.kind == ProcedureKind.Method && - node.name.text == '_#new#tearOff'; - if (inTargetClass && isTearOff) { - inTargetTearOff = true; - } - super.visitProcedure(node); - inTargetTearOff = false; - } - - @override - void defaultConstant(Constant node) { - if (_cache.add(node)) { - super.defaultConstant(node); - } - } - - @override - void defaultConstantReference(Constant node) { - defaultConstant(node); - } - - @override - void visitConstructorInvocation(ConstructorInvocation node) { - final Class parentClass = node.target.parent! as Class; - if (!inTargetTearOff && _matches(parentClass)) { - final Location location = node.location!; - nonConstantLocations.add({ - 'file': location.file.toString(), - 'line': location.line, - 'column': location.column, - }); - } - super.visitConstructorInvocation(node); - } - - @override - void visitClass(Class node) { - inTargetClass = _matches(node); - // check if this is a class that we should ignore - inIgnoredClass = _classShouldBeIgnored(node); - super.visitClass(node); - inTargetClass = false; - 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) || inIgnoredClass) { - return; - } - - final Map instance = {}; - for (final MapEntry kvp in node.fieldValues.entries) { - if (kvp.value is! PrimitiveConstant) { - continue; - } - final PrimitiveConstant value = kvp.value as PrimitiveConstant; - instance[kvp.key.asField.name.text] = value.value; - } - if (_visitedInstances.add(instance.toString())) { - constantInstances.add(instance); - } - } -} - -/// A kernel AST visitor that finds const references. -class ConstFinder { - /// Creates a new ConstFinder class. - /// - /// The `kernelFilePath` is the path to a dill (kernel) file to process. - ConstFinder({ - required String kernelFilePath, - required String classLibraryUri, - required String className, - String? annotationClassLibraryUri, - String? annotationClassName, - }) : _visitor = _ConstVisitor( - kernelFilePath, - classLibraryUri, - className, - annotationClassLibraryUri, - annotationClassName, - ); - - final _ConstVisitor _visitor; - - /// Finds all instances - Map findInstances() { - _visitor._visitedInstances.clear(); - for (final Library library in loadComponentFromBinary(_visitor.kernelFilePath).libraries) { - library.visitChildren(_visitor); - } - return { - 'constantInstances': _visitor.constantInstances, - 'nonConstantLocations': _visitor.nonConstantLocations, - }; - } -} diff --git a/tools/const_finder/test/const_finder_test.dart b/tools/const_finder/test/const_finder_test.dart index 5df4791094465..552c6e7bca691 100644 --- a/tools/const_finder/test/const_finder_test.dart +++ b/tools/const_finder/test/const_finder_test.dart @@ -8,7 +8,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:collection/collection.dart'; -import 'package:const_finder/const_finder.dart'; +import 'package:kernel/const_finder.dart'; import 'package:path/path.dart' as path; void expect(T value, T expected) {