blob: 24c6b70466068398db19fc1140ad5e9ff950f61b [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/analysis/session.dart';
import 'package:analyzer/dart/ast/ast.dart' show CompilationUnit;
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/type_system.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary/summary_sdk.dart';
import 'package:analyzer/src/summary2/ast_binary_writer.dart';
import 'package:analyzer/src/summary2/builder/source_library_builder.dart';
import 'package:analyzer/src/summary2/linked_bundle_context.dart';
import 'package:analyzer/src/summary2/linked_element_factory.dart';
import 'package:analyzer/src/summary2/linked_unit_context.dart';
import 'package:analyzer/src/summary2/reference.dart';
LinkResult link(
AnalysisContext analysisContext,
AnalysisSession analysisSession,
Reference rootReference,
List<LinkedNodeBundle> inputs,
Map<Source, Map<Source, CompilationUnit>> unitMap,
) {
var linker = Linker(analysisContext, analysisSession, rootReference);
linker.link(inputs, unitMap);
return LinkResult(linker.linkingBundle);
}
class Linker {
final AnalysisContext analysisContext;
final AnalysisSession analysisSession;
final Reference rootReference;
LinkedElementFactory elementFactory;
/// References used in all libraries being linked.
/// Element references in [LinkedNode]s are indexes in this list.
final List<Reference> references = [null];
/// The references of the [linkingBundle].
final LinkedNodeReferencesBuilder referencesBuilder =
LinkedNodeReferencesBuilder(
parent: [0],
name: [''],
);
LinkedNodeBundleBuilder linkingBundle;
/// Libraries that are being linked.
final List<SourceLibraryBuilder> builders = [];
TypeProvider typeProvider;
Dart2TypeSystem typeSystem;
Linker(this.analysisContext, this.analysisSession, this.rootReference) {
elementFactory = LinkedElementFactory(
analysisContext,
analysisSession,
rootReference,
);
}
void addSyntheticConstructors() {
for (var library in builders) {
library.addSyntheticConstructors();
}
}
void buildOutlines() {
computeLibraryScopes();
addSyntheticConstructors();
createTypeSystem();
resolveTypes();
performTopLevelInference();
}
void computeLibraryScopes() {
for (var library in builders) {
library.addLocalDeclarations();
}
for (var library in builders) {
library.buildInitialExportScope();
}
for (var library in builders) {
library.addImportsToScope();
}
for (var library in builders) {
library.storeExportScope();
}
// TODO(scheglov) process imports and exports
}
void createTypeSystem() {
var coreRef = rootReference.getChild('dart:core');
var coreLib = elementFactory.elementOfReference(coreRef);
typeProvider = SummaryTypeProvider()..initializeCore(coreLib);
typeSystem = Dart2TypeSystem(typeProvider);
}
int indexOfReference(Reference reference) {
if (reference.parent == null) return 0;
if (reference.index != null) return reference.index;
var parentIndex = indexOfReference(reference.parent);
referencesBuilder.parent.add(parentIndex);
referencesBuilder.name.add(reference.name);
reference.index = references.length;
references.add(reference);
return reference.index;
}
void link(List<LinkedNodeBundle> inputs,
Map<Source, Map<Source, CompilationUnit>> unitMap) {
for (var input in inputs) {
elementFactory.addBundle(input);
}
var linkingLibraries = <LinkedNodeLibraryBuilder>[];
linkingBundle = LinkedNodeBundleBuilder(
references: referencesBuilder,
libraries: linkingLibraries,
);
var bundleContext = LinkedBundleContext(
elementFactory,
linkingBundle.references,
);
for (var librarySource in unitMap.keys) {
var libraryUriStr = librarySource.uri.toString();
var libraryReference = rootReference.getChild(libraryUriStr);
var units = <LinkedNodeUnitBuilder>[];
var libraryNode = LinkedNodeLibraryBuilder(
units: units,
uriStr: libraryUriStr,
);
var libraryBuilder = SourceLibraryBuilder(
this,
elementFactory,
librarySource.uri,
libraryReference,
libraryNode,
);
builders.add(libraryBuilder);
var libraryUnits = unitMap[librarySource];
for (var unitSource in libraryUnits.keys) {
var unit = libraryUnits[unitSource];
var writer = AstBinaryWriter();
var unitData = writer.writeNode(unit);
var unitContext = LinkedUnitContext(bundleContext, writer.tokens);
libraryBuilder.addUnit(unitSource.uri, unitContext, unitData);
libraryNode.units.add(
LinkedNodeUnitBuilder(
uriStr: '${unitSource.uri}',
tokens: writer.tokens,
node: unitData,
),
);
}
linkingLibraries.add(libraryNode);
}
// Add libraries being linked, so we can ask for their elements as well.
elementFactory.addBundle(linkingBundle, context: bundleContext);
buildOutlines();
}
void performTopLevelInference() {
for (var library in builders) {
library.performTopLevelInference();
}
}
void resolveTypes() {
for (var library in builders) {
library.resolveTypes();
}
}
}
class LinkResult {
final LinkedNodeBundleBuilder bundle;
LinkResult(this.bundle);
}