From 3dd1151e3bd533ea5a56dfe91036bf1b89464d43 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 18 Aug 2020 23:16:03 -0700 Subject: [PATCH] Make const_finder work with implemented and extended classes (#20614) --- tools/const_finder/lib/const_finder.dart | 24 +++++++++---- .../const_finder/test/const_finder_test.dart | 17 +++++++++ .../test/fixtures/lib/consts.dart | 8 +++++ .../test/fixtures/lib/target.dart | 36 +++++++++++++++++++ 4 files changed, 78 insertions(+), 7 deletions(-) diff --git a/tools/const_finder/lib/const_finder.dart b/tools/const_finder/lib/const_finder.dart index 481bd24062c..88989059308 100644 --- a/tools/const_finder/lib/const_finder.dart +++ b/tools/const_finder/lib/const_finder.dart @@ -13,11 +13,11 @@ class _ConstVisitor extends RecursiveVisitor { this.classLibraryUri, this.className, ) : assert(kernelFilePath != null), - assert(classLibraryUri != null), - assert(className != null), - _visitedInstances = {}, - constantInstances = >[], - nonConstantLocations = >[]; + assert(classLibraryUri != null), + assert(className != null), + _visitedInstances = {}, + constantInstances = >[], + nonConstantLocations = >[]; /// The path to the file to open. final String kernelFilePath; @@ -32,9 +32,19 @@ class _ConstVisitor extends RecursiveVisitor { final List> constantInstances; final List> nonConstantLocations; + // A cache of previously evaluated classes. + static Map _classHeirarchyCache = {}; bool _matches(Class node) { - return node.enclosingLibrary.importUri.toString() == classLibraryUri && - node.name == className; + assert(node != null); + final bool result = _classHeirarchyCache[node]; + if (result != null) { + return result; + } + final bool exactMatch = node.name == className + && node.enclosingLibrary.importUri.toString() == classLibraryUri; + _classHeirarchyCache[node] = exactMatch + || node.supers.any((Supertype supertype) => _matches(supertype.classNode)); + return _classHeirarchyCache[node]; } // Avoid visiting the same constant more than once. diff --git a/tools/const_finder/test/const_finder_test.dart b/tools/const_finder/test/const_finder_test.dart index c3b1a8dc20c..e68146761b0 100644 --- a/tools/const_finder/test/const_finder_test.dart +++ b/tools/const_finder/test/const_finder_test.dart @@ -71,11 +71,28 @@ void _checkConsts() { {'stringValue': '10', 'intValue': 10, 'targetValue': null}, {'stringValue': '9', 'intValue': 9}, {'stringValue': '7', 'intValue': 7, 'targetValue': null}, + {'stringValue': '11', 'intValue': 11, 'targetValue': null}, + {'stringValue': '12', 'intValue': 12, 'targetValue': null}, {'stringValue': 'package', 'intValue':-1, 'targetValue': null}, ], 'nonConstantLocations': [], }), ); + + final ConstFinder finder2 = ConstFinder( + kernelFilePath: constsDill, + classLibraryUri: 'package:const_finder_fixtures/target.dart', + className: 'MixedInTarget', + ); + expect( + jsonEncode(finder2.findInstances()), + jsonEncode({ + 'constantInstances': >[ + {'val': '13'}, + ], + 'nonConstantLocations': [], + }), + ); } void _checkNonConsts() { diff --git a/tools/const_finder/test/fixtures/lib/consts.dart b/tools/const_finder/test/fixtures/lib/consts.dart index 4095df150c9..b5a7e10f138 100644 --- a/tools/const_finder/test/fixtures/lib/consts.dart +++ b/tools/const_finder/test/fixtures/lib/consts.dart @@ -31,6 +31,14 @@ void main() { final StaticConstInitializer staticConstMap = StaticConstInitializer(); staticConstMap.useOne(1); + + const ExtendsTarget extendsTarget = ExtendsTarget('11', 11, null); + extendsTarget.hit(); + const ImplementsTarget implementsTarget = ImplementsTarget('12', 12, null); + implementsTarget.hit(); + + const MixedInTarget mixedInTraget = MixedInTarget('13'); + mixedInTraget.hit(); } class IgnoreMe { diff --git a/tools/const_finder/test/fixtures/lib/target.dart b/tools/const_finder/test/fixtures/lib/target.dart index 4046216970e..bdaee2d3615 100644 --- a/tools/const_finder/test/fixtures/lib/target.dart +++ b/tools/const_finder/test/fixtures/lib/target.dart @@ -13,3 +13,39 @@ class Target { print('$stringValue $intValue'); } } + +class ExtendsTarget extends Target { + const ExtendsTarget(String stringValue, int intValue, Target targetValue) + : super(stringValue, intValue, targetValue); +} + +class ImplementsTarget implements Target { + const ImplementsTarget(this.stringValue, this.intValue, this.targetValue); + + @override + final String stringValue; + @override + final int intValue; + @override + final Target targetValue; + + @override + void hit() { + print('ImplementsTarget - $stringValue $intValue'); + } +} + +mixin MixableTarget { + String get val; + + void hit() { + print(val); + } +} + +class MixedInTarget with MixableTarget { + const MixedInTarget(this.val); + + @override + final String val; +} \ No newline at end of file