blob: 01ddaa65303a6ecf2bbfa28cf2291fcfbc1944f2 [file] [log] [blame]
// 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 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/dart/analysis/session.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/summary2/bundle_reader.dart';
import 'package:analyzer/src/summary2/reference.dart';
class LinkedElementFactory {
final AnalysisContextImpl analysisContext;
AnalysisSessionImpl analysisSession;
final Reference rootReference;
final Map<String, LibraryReader> _libraryReaders = {};
final Map<String, List<Reference>> _exportsOfLibrary = {};
bool isApplyingInformativeData = false;
LinkedElementFactory(
this.analysisContext,
this.analysisSession,
this.rootReference,
) {
ArgumentError.checkNotNull(analysisContext, 'analysisContext');
ArgumentError.checkNotNull(analysisSession, 'analysisSession');
}
Reference get dynamicRef {
return rootReference.getChild('dart:core').getChild('dynamic');
}
void addBundle(BundleReader bundle) {
addLibraries(bundle.libraryMap);
}
void addLibraries(Map<String, LibraryReader> libraries) {
_libraryReaders.addAll(libraries);
}
Namespace buildExportNamespace(Uri uri) {
var exportedNames = <String, Element>{};
var exportedReferences = exportsOfLibrary('$uri');
for (var exportedReference in exportedReferences) {
var element = elementOfReference(exportedReference);
// TODO(scheglov) Remove after https://github.com/dart-lang/sdk/issues/41212
if (element == null) {
throw StateError(
'[No element]'
'[uri: $uri]'
'[exportedReferences: $exportedReferences]'
'[exportedReference: $exportedReference]',
);
}
exportedNames[element.name!] = element;
}
return Namespace(exportedNames);
}
LibraryElementImpl? createLibraryElementForReading(String uriStr) {
var sourceFactory = analysisContext.sourceFactory;
var librarySource = sourceFactory.forUri(uriStr);
// The URI cannot be resolved, we don't know the library.
if (librarySource == null) return null;
var reader = _libraryReaders[uriStr];
if (reader == null) {
var libraryUriList = rootReference.children.map((e) => e.name).toList();
throw ArgumentError(
'Missing library: $uriStr\n'
'Available libraries: $libraryUriList',
);
}
var libraryElement = reader.readElement(
librarySource: librarySource,
);
setLibraryTypeSystem(libraryElement);
return libraryElement;
}
void createTypeProviders(
LibraryElementImpl dartCore,
LibraryElementImpl dartAsync,
) {
if (analysisContext.hasTypeProvider) {
return;
}
analysisContext.setTypeProviders(
legacy: TypeProviderImpl(
coreLibrary: dartCore,
asyncLibrary: dartAsync,
isNonNullableByDefault: false,
),
nonNullableByDefault: TypeProviderImpl(
coreLibrary: dartCore,
asyncLibrary: dartAsync,
isNonNullableByDefault: true,
),
);
// During linking we create libraries when typeProvider is not ready.
// Update these libraries now, when typeProvider is ready.
for (var reference in rootReference.children) {
var libraryElement = reference.element as LibraryElementImpl?;
if (libraryElement != null && !libraryElement.hasTypeProviderSystemSet) {
setLibraryTypeSystem(libraryElement);
}
}
}
Element? elementOfReference(Reference reference) {
if (reference.element != null) {
return reference.element;
}
if (reference.parent == null) {
return null;
}
if (reference.isLibrary) {
var uriStr = reference.name;
return createLibraryElementForReading(uriStr);
}
var parent = reference.parent!.parent!;
var parentElement = elementOfReference(parent);
if (parentElement is ClassElementImpl) {
var linkedData = parentElement.linkedData;
if (linkedData is ClassElementLinkedData) {
linkedData.readMembers(parentElement);
}
}
var element = reference.element;
if (element == null) {
throw StateError('Expected existing element: $reference');
}
return element;
}
List<Reference> exportsOfLibrary(String uriStr) {
var exports = _exportsOfLibrary[uriStr];
if (exports != null) return exports;
// TODO(scheglov) Use [setExportsOfLibrary] instead
var library = _libraryReaders[uriStr];
if (library == null) return const [];
return library.exports;
}
bool hasLibrary(String uriStr) {
// We already have the element, linked or read.
if (rootReference[uriStr]?.element is LibraryElementImpl) {
return true;
}
// No element yet, but we know how to read it.
return _libraryReaders[uriStr] != null;
}
LibraryElementImpl? libraryOfUri(String uriStr) {
var reference = rootReference.getChild(uriStr);
return elementOfReference(reference) as LibraryElementImpl?;
}
LibraryElementImpl libraryOfUri2(String uriStr) {
var element = libraryOfUri(uriStr);
if (element == null) {
libraryOfUri(uriStr);
throw StateError('No library: $uriStr');
}
return element;
}
/// Return the [LibraryElementImpl] if it is ready.
LibraryElementImpl? libraryOfUriIfReady(String uriStr) {
var element = rootReference.getChild(uriStr).element;
return element is LibraryElementImpl ? element : null;
}
/// We have linked the bundle, and need to disconnect its libraries, so
/// that the client can re-add the bundle, this time read from bytes.
void removeBundle(Set<String> uriStrSet) {
removeLibraries(uriStrSet);
}
/// Remove libraries with the specified URIs from the reference tree, and
/// any session level caches.
void removeLibraries(Set<String> uriStrSet) {
for (var uriStr in uriStrSet) {
_exportsOfLibrary.remove(uriStr);
_libraryReaders.remove(uriStr);
rootReference.removeChild(uriStr);
}
analysisSession.classHierarchy.removeOfLibraries(uriStrSet);
analysisSession.inheritanceManager.removeOfLibraries(uriStrSet);
// If we discard `dart:core` and `dart:async`, we should also discard
// the type provider.
if (uriStrSet.contains('dart:core')) {
if (!uriStrSet.contains('dart:async')) {
throw StateError(
'Expected to link dart:core and dart:async together: '
'${uriStrSet.toList()}',
);
}
if (_libraryReaders.isNotEmpty) {
throw StateError(
'Expected to link dart:core and dart:async first: '
'${_libraryReaders.keys.toList()}',
);
}
analysisContext.clearTypeProvider();
}
}
void replaceAnalysisSession(AnalysisSessionImpl newSession) {
analysisSession = newSession;
for (var libraryReference in rootReference.children) {
var libraryElement = libraryReference.element;
if (libraryElement is LibraryElementImpl) {
libraryElement.session = newSession;
}
}
}
/// Set exports of the library with [uriStr], after building exports during
/// linking, or after reading a linked bundle.
void setExportsOfLibrary(String uriStr, List<Reference> exports) {
_exportsOfLibrary[uriStr] = exports;
}
void setLibraryTypeSystem(LibraryElementImpl libraryElement) {
// During linking we create libraries when typeProvider is not ready.
// And if we link dart:core and dart:async, we cannot create it.
// We will set typeProvider later, during [createTypeProviders].
if (!analysisContext.hasTypeProvider) {
return;
}
var isNonNullable = libraryElement.isNonNullableByDefault;
libraryElement.typeProvider = isNonNullable
? analysisContext.typeProviderNonNullableByDefault
: analysisContext.typeProviderLegacy;
libraryElement.typeSystem = isNonNullable
? analysisContext.typeSystemNonNullableByDefault
: analysisContext.typeSystemLegacy;
libraryElement.hasTypeProviderSystemSet = true;
libraryElement.createLoadLibraryFunction();
}
}