From 4193bb38468a109d8df7e62940f8949695a86d07 Mon Sep 17 00:00:00 2001 From: Martin Kustermann Date: Wed, 24 Aug 2022 13:53:49 +0000 Subject: [PATCH] [analyzer] Remove the [ImportedElement] class When running analyzer on flutter and it's transitive sources, it consumes around 480 MB of memory. The [ImportedElement] class is an intermediatey wrapper around an [Element] and a boolean that is mostly false. This CL removes the [ImportedElement] class and stores the boolean side-information alongside the element in [PrefixScope] and [PrefixScopeLookupResult]. This saves around 15.5 MB of memory. TEST=ci Change-Id: I94692a9709c70decd90c604bbdc85f5b308b3006 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/256029 Reviewed-by: Brian Wilkerson Commit-Queue: Martin Kustermann --- pkg/analyzer/lib/src/dart/element/scope.dart | 119 +++++++++--------- .../lib/src/generated/scope_helpers.dart | 25 ++-- 2 files changed, 73 insertions(+), 71 deletions(-) diff --git a/pkg/analyzer/lib/src/dart/element/scope.dart b/pkg/analyzer/lib/src/dart/element/scope.dart index 2c8911900152..d1d6cb073fc0 100644 --- a/pkg/analyzer/lib/src/dart/element/scope.dart +++ b/pkg/analyzer/lib/src/dart/element/scope.dart @@ -85,20 +85,6 @@ class FormalParameterScope extends EnclosedScope { } } -class ImportedElement { - final Element element; - - /// This flag is set to `true` if [element] is available using import - /// directives where every imported library re-exports the element, and - /// every such `export` directive is marked as deprecated. - final bool isFromDeprecatedExport; - - ImportedElement({ - required this.element, - required this.isFromDeprecatedExport, - }); -} - /// The scope defined by an interface element. class InterfaceScope extends EnclosedScope { InterfaceScope(super.parent, InterfaceElement element) { @@ -158,8 +144,10 @@ class LocalScope extends EnclosedScope { class PrefixScope implements Scope { final LibraryOrAugmentationElementImpl _container; - final Map _getters = {}; - final Map _setters = {}; + final Map _getters = {}; + final Map _setters = {}; + Set? _settersFromDeprecatedExport; + Set? _gettersFromDeprecatedExport; final Set _extensions = {}; LibraryElement? _deferredLibrary; @@ -176,12 +164,8 @@ class PrefixScope implements Scope { final reference = exportedReference.reference; if (combinators.allows(reference.name)) { final element = elementFactory.elementOfReference(reference)!; - final importedElement = ImportedElement( - element: element, - isFromDeprecatedExport: - _isFromDeprecatedExport(importedLibrary, exportedReference), - ); - _add(importedElement); + _add(element, + _isFromDeprecatedExport(importedLibrary, exportedReference)); } } if (import.prefix is DeferredImportElementPrefix) { @@ -199,48 +183,56 @@ class PrefixScope implements Scope { return ScopeLookupResultImpl(deferredLibrary.loadLibraryFunction, null); } - var getter = _getters[id]; - var setter = _setters[id]; - return PrefixScopeLookupResult(getter, setter); + return PrefixScopeLookupResult( + _getters[id], + _setters[id], + _gettersFromDeprecatedExport?.contains(id) ?? false, + _settersFromDeprecatedExport?.contains(id) ?? false); } - void _add(ImportedElement imported) { - final element = imported.element; + void _add(Element element, bool isFromDeprecatedExport) { if (element is PropertyAccessorElement && element.isSetter) { - _addTo(map: _setters, incoming: imported); + _addTo(element, isFromDeprecatedExport, isSetter: true); } else { - _addTo(map: _getters, incoming: imported); + _addTo(element, isFromDeprecatedExport, isSetter: false); if (element is ExtensionElement) { _extensions.add(element); } } } - void _addTo({ - required Map map, - required ImportedElement incoming, - }) { - final id = incoming.element.displayName; + void _addTo(Element element, bool isDeprecatedExport, + {required bool isSetter}) { + final map = isSetter ? _setters : _getters; + final id = element.displayName; final existing = map[id]; if (existing == null) { - map[id] = incoming; + map[id] = element; + if (isDeprecatedExport) { + if (isSetter) { + (_settersFromDeprecatedExport ??= {}).add(id); + } else { + (_gettersFromDeprecatedExport ??= {}).add(id); + } + } return; } - if (existing.element == incoming.element) { - map[id] = ImportedElement( - element: incoming.element, - isFromDeprecatedExport: - existing.isFromDeprecatedExport && incoming.isFromDeprecatedExport, - ); + final deprecatedSet = + isSetter ? _settersFromDeprecatedExport : _gettersFromDeprecatedExport; + final wasFromDeprecatedExport = deprecatedSet?.contains(id) ?? false; + if (existing == element) { + if (wasFromDeprecatedExport && !isDeprecatedExport) { + deprecatedSet!.remove(id); + } return; } - map[id] = ImportedElement( - element: _merge(existing.element, incoming.element), - isFromDeprecatedExport: false, - ); + map[id] = _merge(existing, element); + if (wasFromDeprecatedExport) { + deprecatedSet!.remove(id); + } } Element _merge(Element existing, Element other) { @@ -305,20 +297,35 @@ class PrefixScope implements Scope { } } -class PrefixScopeLookupResult implements ScopeLookupResult { - final ImportedElement? importedGetter; - final ImportedElement? importedSetter; +class PrefixScopeLookupResult extends ScopeLookupResultImpl { + static const int getterIsFromDeprecatedExportBit = 1 << 0; + static const int setterIsFromDeprecatedExportBit = 1 << 1; - PrefixScopeLookupResult( - this.importedGetter, - this.importedSetter, - ); + final int _deprecatedBits; - @override - Element? get getter => importedGetter?.element; + PrefixScopeLookupResult( + super.importedGetter, + super.importedSetter, + bool getterIsFromDeprecatedExport, + bool setterIsFromDeprecatedExport, + ) : _deprecatedBits = (getterIsFromDeprecatedExport + ? getterIsFromDeprecatedExportBit + : 0) | + (setterIsFromDeprecatedExport + ? setterIsFromDeprecatedExportBit + : 0); + + /// This flag is set to `true` if [getter] is available using import + /// directives where every imported library re-exports the element, and + /// every such `export` directive is marked as deprecated. + bool get getterIsFromDeprecatedExport => + (_deprecatedBits & getterIsFromDeprecatedExportBit) != 0; - @override - Element? get setter => importedSetter?.element; + /// This flag is set to `true` if [setter] is available using import + /// directives where every imported library re-exports the element, and + /// every such `export` directive is marked as deprecated. + bool get setterIsFromDeprecatedExport => + (_deprecatedBits & setterIsFromDeprecatedExportBit) != 0; } class ScopeLookupResultImpl implements ScopeLookupResult { diff --git a/pkg/analyzer/lib/src/generated/scope_helpers.dart b/pkg/analyzer/lib/src/generated/scope_helpers.dart index a49da264e540..8d2feb23ab07 100644 --- a/pkg/analyzer/lib/src/generated/scope_helpers.dart +++ b/pkg/analyzer/lib/src/generated/scope_helpers.dart @@ -39,10 +39,10 @@ mixin ScopeHelpers { required ScopeLookupResult scopeLookupResult, required SimpleIdentifier node, }) { - if (scopeLookupResult is PrefixScopeLookupResult) { + if (scopeLookupResult is PrefixScopeLookupResult && + scopeLookupResult.getterIsFromDeprecatedExport) { _reportDeprecatedExportUse( node: node, - imported: scopeLookupResult.importedGetter, ); } } @@ -51,24 +51,19 @@ mixin ScopeHelpers { required ScopeLookupResult scopeLookupResult, required SimpleIdentifier node, }) { - if (scopeLookupResult is PrefixScopeLookupResult) { + if (scopeLookupResult is PrefixScopeLookupResult && + scopeLookupResult.setterIsFromDeprecatedExport) { _reportDeprecatedExportUse( node: node, - imported: scopeLookupResult.importedSetter, ); } } - void _reportDeprecatedExportUse({ - required SimpleIdentifier node, - required final ImportedElement? imported, - }) { - if (imported != null && imported.isFromDeprecatedExport) { - errorReporter.reportErrorForNode( - HintCode.DEPRECATED_EXPORT_USE, - node, - [node.name], - ); - } + void _reportDeprecatedExportUse({required SimpleIdentifier node}) { + errorReporter.reportErrorForNode( + HintCode.DEPRECATED_EXPORT_USE, + node, + [node.name], + ); } }