blob: e99dd4ea3d50278512388735b5b8e798f2417140 [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/element/element.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary2/linked_bundle_context.dart';
import 'package:analyzer/src/summary2/linked_unit_context.dart';
import 'package:analyzer/src/summary2/reference.dart';
class LinkedElementFactory {
final AnalysisContext analysisContext;
final AnalysisSession analysisSession;
final Reference rootReference;
final Map<String, _Library> libraryMap = {};
LinkedElementFactory(
this.analysisContext, this.analysisSession, this.rootReference);
void addBundle(LinkedNodeBundle bundle, {LinkedBundleContext context}) {
context ??= LinkedBundleContext(this, bundle.references);
for (var library in bundle.libraries) {
libraryMap[library.uriStr] = _Library(context, library);
}
}
LinkedBundleContext bundleContextOfLibrary(String uriStr) {
return libraryMap[uriStr].context;
}
Element elementOfReference(Reference reference) {
if (reference.element != null) {
return reference.element;
}
return _ElementRequest(this, reference).elementOfReference(reference);
}
List<Reference> exportsOfLibrary(String uriStr) {
var library = libraryMap[uriStr];
var exportIndexList = library.node.exports;
var exportReferences = List<Reference>(exportIndexList.length);
for (var i = 0; i < exportIndexList.length; ++i) {
var index = exportIndexList[i];
var reference = library.context.referenceOfIndex(index);
exportReferences[i] = reference;
}
return exportReferences;
}
}
class _ElementRequest {
final LinkedElementFactory elementFactory;
final Reference input;
_ElementRequest(this.elementFactory, this.input);
ClassElementImpl createClassElement(
CompilationUnitElementImpl unit, Reference reference) {
if (reference.node == null) {
indexUnitDeclarations(unit);
assert(reference.node != 0, '$reference');
}
return reference.element = ClassElementImpl.forLinkedNode(
unit,
reference,
reference.node,
);
}
LibraryElementImpl createLibraryElement(Reference reference) {
// TODO(scheglov) use actual values
var libraryElement = LibraryElementImpl(elementFactory.analysisContext,
elementFactory.analysisSession, '', -1, 0);
var uriStr = reference.name;
var sourceFactory = elementFactory.analysisContext.sourceFactory;
var libraryData = elementFactory.libraryMap[uriStr];
var librarySource = sourceFactory.forUri(uriStr);
var units = <CompilationUnitElementImpl>[];
var unitContainerRef = reference.getChild('@unit');
for (var unitData in libraryData.node.units) {
var unitSource = sourceFactory.forUri(unitData.uriStr);
var unitElement = CompilationUnitElementImpl.forLinkedNode(
libraryElement,
LinkedUnitContext(libraryData.context, unitData.tokens),
unitContainerRef.getChild(unitData.uriStr),
unitData.node,
);
unitElement.source = unitSource;
unitElement.librarySource = librarySource;
units.add(unitElement);
unitContainerRef.getChild(unitData.uriStr).element = unitElement;
}
libraryElement.definingCompilationUnit = units[0];
libraryElement.parts = units.skip(1).toList();
return reference.element = libraryElement;
}
ElementImpl elementOfReference(Reference reference) {
if (reference.element != null) {
return reference.element;
}
var parent2 = reference.parent.parent;
if (parent2 == null) {
return createLibraryElement(reference);
}
var parentName = reference.parent.name;
if (parentName == '@class') {
var unit = elementOfReference(parent2);
return createClassElement(unit, reference);
}
if (parentName == '@unit') {
elementOfReference(parent2);
// Creating a library fills all its units.
assert(reference.element != null);
return reference.element;
}
// TODO(scheglov) support other elements
throw StateError('Not found: $input');
}
void indexUnitDeclarations(CompilationUnitElementImpl unit) {
var context = unit.linkedContext;
var classRef = unit.reference.getChild('@class');
for (var declaration in unit.linkedNode.compilationUnit_declarations) {
var kind = declaration.kind;
if (kind == LinkedNodeKind.classDeclaration ||
kind == LinkedNodeKind.classTypeAlias) {
var name = context.getUnitMemberName(declaration);
classRef.getChild(name).node = declaration;
} else {
// TODO(scheglov) support other elements
throw UnimplementedError('$kind');
}
}
}
}
class _Library {
final LinkedBundleContext context;
final LinkedNodeLibrary node;
_Library(this.context, this.node);
}