| // Copyright (c) 2019, 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:typed_data'; |
| |
| import 'package:analyzer/dart/analysis/declared_variables.dart'; |
| import 'package:analyzer/dart/ast/ast.dart' as ast; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/src/context/context.dart'; |
| import 'package:analyzer/src/dart/analysis/file_state.dart'; |
| import 'package:analyzer/src/dart/element/element.dart'; |
| import 'package:analyzer/src/dart/element/inheritance_manager3.dart'; |
| import 'package:analyzer/src/dart/element/name_union.dart'; |
| import 'package:analyzer/src/fine/library_manifest.dart'; |
| import 'package:analyzer/src/summary2/bundle_writer.dart'; |
| import 'package:analyzer/src/summary2/detach_nodes.dart'; |
| import 'package:analyzer/src/summary2/enclosing_type_parameters_flag.dart'; |
| import 'package:analyzer/src/summary2/export.dart'; |
| import 'package:analyzer/src/summary2/library_builder.dart'; |
| import 'package:analyzer/src/summary2/linked_element_factory.dart'; |
| import 'package:analyzer/src/summary2/reference.dart'; |
| import 'package:analyzer/src/summary2/simply_bounded.dart'; |
| import 'package:analyzer/src/summary2/super_constructor_resolver.dart'; |
| import 'package:analyzer/src/summary2/top_level_inference.dart'; |
| import 'package:analyzer/src/summary2/type_alias.dart'; |
| import 'package:analyzer/src/summary2/types_builder.dart'; |
| import 'package:analyzer/src/summary2/variance_builder.dart'; |
| import 'package:analyzer/src/util/performance/operation_performance.dart'; |
| import 'package:analyzer/src/utilities/uri_cache.dart'; |
| |
| LinkResult link({ |
| required LinkedElementFactory elementFactory, |
| required OperationPerformanceImpl performance, |
| required List<LibraryFileKind> inputLibraries, |
| required String apiSignature, |
| }) { |
| var linker = Linker( |
| elementFactory: elementFactory, |
| apiSignature: apiSignature, |
| ); |
| linker.link(performance: performance, inputLibraries: inputLibraries); |
| |
| return LinkResult(resolutionBytes: linker.resolutionBytes); |
| } |
| |
| class Linker { |
| final LinkedElementFactory elementFactory; |
| final String apiSignature; |
| |
| /// Libraries that are being linked. |
| final Map<Uri, LibraryBuilder> builders = {}; |
| |
| final Map<Object, ast.AstNode> elementNodes = Map.identity(); |
| |
| late InheritanceManager3 inheritance; // TODO(scheglov): cache it |
| |
| Map<Uri, LibraryManifest> newLibraryManifests = {}; |
| late Uint8List resolutionBytes; |
| |
| Linker({required this.elementFactory, required this.apiSignature}); |
| |
| AnalysisContextImpl get analysisContext { |
| return elementFactory.analysisContext; |
| } |
| |
| DeclaredVariables get declaredVariables { |
| return analysisContext.declaredVariables; |
| } |
| |
| Reference get rootReference => elementFactory.rootReference; |
| |
| bool get _isLinkingDartCore { |
| var dartCoreUri = uriCache.parse('dart:core'); |
| return builders.containsKey(dartCoreUri); |
| } |
| |
| /// If the [element] is part of a library being linked, return the node |
| /// from which it was created. |
| ast.AstNode? getLinkingNode(FragmentImpl element) { |
| return elementNodes[element]; |
| } |
| |
| /// If the [fragment] is part of a library being linked, return the node |
| /// from which it was created. |
| ast.AstNode? getLinkingNode2(Fragment fragment) { |
| return elementNodes[fragment]; |
| } |
| |
| void link({ |
| required OperationPerformanceImpl performance, |
| required List<LibraryFileKind> inputLibraries, |
| }) { |
| performance.run('LibraryBuilder.build', (performance) { |
| for (var inputLibrary in inputLibraries) { |
| LibraryBuilder.build( |
| linker: this, |
| inputLibrary: inputLibrary, |
| performance: performance, |
| ); |
| } |
| }); |
| |
| performance.run('buildOutlines', (performance) { |
| _buildOutlines(performance: performance); |
| }); |
| |
| performance.run('writeLibraries', (performance) { |
| _writeLibraries(performance: performance); |
| }); |
| } |
| |
| void _buildClassSyntheticConstructors() { |
| for (var library in builders.values) { |
| library.buildClassSyntheticConstructors(); |
| } |
| } |
| |
| void _buildElementNameUnions() { |
| for (var builder in builders.values) { |
| var element = builder.element; |
| element.nameUnion = ElementNameUnion.forLibrary(element); |
| } |
| } |
| |
| void _buildEnumChildren() { |
| for (var library in builders.values) { |
| library.buildEnumChildren(); |
| } |
| } |
| |
| void _buildEnumSyntheticConstructors() { |
| for (var library in builders.values) { |
| library.buildEnumSyntheticConstructors(); |
| } |
| } |
| |
| void _buildExportScopes() { |
| for (var library in builders.values) { |
| library.buildInitialExportScope(); |
| } |
| |
| var exportingBuilders = <LibraryBuilder>{}; |
| var exportedBuilders = <LibraryBuilder>{}; |
| |
| for (var library in builders.values) { |
| library.addExporters(); |
| } |
| |
| for (var library in builders.values) { |
| if (library.exports.isNotEmpty) { |
| exportedBuilders.add(library); |
| for (var export in library.exports) { |
| exportingBuilders.add(export.exporter); |
| } |
| } |
| } |
| |
| var both = <LibraryBuilder>{}; |
| for (var exported in exportedBuilders) { |
| if (exportingBuilders.contains(exported)) { |
| both.add(exported); |
| } |
| for (var export in exported.exports) { |
| exported.exportScope.forEach(export.addToExportScope); |
| } |
| } |
| |
| // We keep a queue of exports to propagate. |
| // First we loop over every reference that both exports and is exported, |
| // but then we only process the exports that should be propagated. |
| var additionalExportData = <_AdditionalExport>[]; |
| |
| void addExport(Export export, String name, ExportedReference reference) { |
| if (export.addToExportScope(name, reference)) { |
| // We've added [name] to [export.exporter]s export scope. |
| // We need to propagate that to anyone that exports that library. |
| additionalExportData.add( |
| _AdditionalExport(export.exporter, name, reference), |
| ); |
| } |
| } |
| |
| for (var exported in both) { |
| for (var export in exported.exports) { |
| exported.exportScope.forEach((name, reference) { |
| addExport(export, name, reference); |
| }); |
| } |
| } |
| |
| while (additionalExportData.isNotEmpty) { |
| var data = additionalExportData.removeLast(); |
| for (var export in data.exported.exports) { |
| addExport(export, data.name, data.reference); |
| } |
| } |
| |
| assert(() { |
| for (var exported in both) { |
| for (var export in exported.exports) { |
| exported.exportScope.forEach((name, reference) { |
| if (export.addToExportScope(name, reference)) { |
| throw "Error in export calculation: Assert failed."; |
| } |
| }); |
| } |
| } |
| return true; |
| }(), true); |
| |
| for (var library in builders.values) { |
| library.storeExportScope(); |
| } |
| } |
| |
| void _buildOutlines({required OperationPerformanceImpl performance}) { |
| _createTypeSystemIfNotLinkingDartCore(); |
| |
| performance.run('computeLibraryScopes', (performance) { |
| _computeLibraryScopes(performance: performance); |
| }); |
| |
| _createTypeSystem(); |
| _resolveTypes(); |
| _setDefaultSupertypes(); |
| |
| _buildClassSyntheticConstructors(); |
| _buildEnumSyntheticConstructors(); |
| _replaceConstFieldsIfNoConstConstructor(); |
| _resolveConstructorFieldFormals(); |
| _buildEnumChildren(); |
| _computeFieldPromotability(); |
| SuperConstructorResolver(this).perform(); |
| _performTopLevelInference(); |
| _resolveConstructors(); |
| _resolveConstantInitializers(); |
| _resolveDefaultValues(); |
| _resolveMetadata(); |
| |
| _collectMixinSuperInvokedNames(); |
| EnclosingTypeParameterReferenceFlag(this).perform(); |
| _buildElementNameUnions(); |
| _detachNodes(); |
| } |
| |
| void _collectMixinSuperInvokedNames() { |
| for (var library in builders.values) { |
| library.collectMixinSuperInvokedNames(); |
| } |
| } |
| |
| void _computeFieldPromotability() { |
| for (var library in builders.values) { |
| library.computeFieldPromotability(); |
| } |
| } |
| |
| void _computeLibraryScopes({required OperationPerformanceImpl performance}) { |
| for (var library in builders.values) { |
| library.buildElements(); |
| } |
| |
| _buildExportScopes(); |
| } |
| |
| void _createTypeSystem() { |
| elementFactory.createTypeProviders( |
| elementFactory.dartCoreElement, |
| elementFactory.dartAsyncElement, |
| ); |
| |
| inheritance = InheritanceManager3(); |
| } |
| |
| /// To resolve macro annotations we need to access exported namespaces of |
| /// imported (and already linked) libraries. While computing it we might |
| /// need `Null` from `dart:core` (to convert null safe types to legacy). |
| void _createTypeSystemIfNotLinkingDartCore() { |
| if (!_isLinkingDartCore) { |
| _createTypeSystem(); |
| } |
| } |
| |
| void _detachNodes() { |
| for (var builder in builders.values) { |
| detachElementsFromNodes(builder.element); |
| } |
| } |
| |
| void _performTopLevelInference() { |
| TopLevelInference(this).infer(); |
| } |
| |
| void _replaceConstFieldsIfNoConstConstructor() { |
| for (var library in builders.values) { |
| library.replaceConstFieldsIfNoConstConstructor(); |
| } |
| } |
| |
| void _resolveConstantInitializers() { |
| ConstantInitializersResolver(this).perform(); |
| } |
| |
| void _resolveConstructorFieldFormals() { |
| for (var library in builders.values) { |
| library.resolveConstructorFieldFormals(); |
| } |
| } |
| |
| void _resolveConstructors() { |
| for (var library in builders.values) { |
| library.resolveConstructors(); |
| } |
| } |
| |
| void _resolveDefaultValues() { |
| for (var library in builders.values) { |
| library.resolveDefaultValues(); |
| } |
| } |
| |
| void _resolveMetadata() { |
| for (var library in builders.values) { |
| library.resolveMetadata(); |
| } |
| } |
| |
| void _resolveTypes() { |
| var nodesToBuildType = NodesToBuildType(); |
| for (var library in builders.values) { |
| library.resolveTypes(nodesToBuildType); |
| } |
| VarianceBuilder(this).perform(); |
| computeSimplyBounded(this); |
| TypeAliasSelfReferenceFinder().perform(this); |
| TypesBuilder(this).build(nodesToBuildType); |
| } |
| |
| void _setDefaultSupertypes() { |
| for (var library in builders.values) { |
| library.setDefaultSupertypes(); |
| } |
| } |
| |
| void _writeLibraries({required OperationPerformanceImpl performance}) { |
| var bundleWriter = BundleWriter(); |
| |
| for (var builder in builders.values) { |
| bundleWriter.writeLibraryElement(builder.element); |
| } |
| |
| var writeWriterResult = performance.run('bundleWriteFinish', (performance) { |
| return bundleWriter.finish(); |
| }); |
| resolutionBytes = writeWriterResult.resolutionBytes; |
| |
| performance.getDataInt('length').add(resolutionBytes.length); |
| } |
| } |
| |
| class LinkResult { |
| final Uint8List resolutionBytes; |
| |
| LinkResult({required this.resolutionBytes}); |
| } |
| |
| class _AdditionalExport { |
| final LibraryBuilder exported; |
| final String name; |
| final ExportedReference reference; |
| |
| _AdditionalExport(this.exported, this.name, this.reference); |
| } |