blob: 7653ed633245dec4192c1e887c0f7dfd208a6bae [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';
import 'package:analyzer/src/summary2/tokens_context.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);
}
}
Element elementOfReference(Reference reference) {
if (reference.element != null) {
return reference.element;
}
if (reference.parent == null) {
return null;
}
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;
}
LibraryElementImpl libraryOfUri(String uriStr) {
var reference = rootReference.getChild(uriStr);
return elementOfReference(reference);
}
}
class _ElementRequest {
final LinkedElementFactory elementFactory;
final Reference input;
_ElementRequest(this.elementFactory, this.input);
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 _class(unit, reference);
}
if (parentName == '@constructor') {
var class_ = elementOfReference(parent2);
return _constructor(class_, reference);
}
if (parentName == '@function') {
CompilationUnitElementImpl enclosing = elementOfReference(parent2);
return _function(enclosing, reference);
}
if (parentName == '@getter') {
var enclosing = elementOfReference(parent2);
return _getter(enclosing, reference);
}
if (parentName == '@method') {
var enclosing = elementOfReference(parent2);
return _method(enclosing, reference);
}
if (parentName == '@parameter') {
ExecutableElementImpl enclosing = elementOfReference(parent2);
return _parameter(enclosing, reference);
}
if (parentName == '@typeAlias') {
var unit = elementOfReference(parent2);
return _typeAlias(unit, reference);
}
if (parentName == '@typeParameter') {
var enclosing = elementOfReference(parent2) as TypeParameterizedElement;
return _typeParameter(enclosing, 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');
}
ClassElementImpl _class(
CompilationUnitElementImpl unit, Reference reference) {
if (reference.node == null) {
_indexUnitDeclarations(unit);
assert(reference.node != 0, '$reference');
}
return reference.element = ClassElementImpl.forLinkedNode(
unit,
reference,
reference.node,
);
}
ConstructorElementImpl _constructor(
ClassElementImpl class_, Reference reference) {
return reference.element = ConstructorElementImpl.forLinkedNode(
reference,
reference.node,
class_,
);
}
LibraryElementImpl _createLibraryElement(Reference reference) {
var uriStr = reference.name;
var sourceFactory = elementFactory.analysisContext.sourceFactory;
var librarySource = sourceFactory.forUri(uriStr);
var libraryData = elementFactory.libraryMap[uriStr];
var node = libraryData.node;
var hasName = node.name.isNotEmpty;
var definingUnitData = node.units[0];
var definingUnitContext = LinkedUnitContext(
libraryData.context,
TokensContext(definingUnitData.tokens),
);
var libraryElement = LibraryElementImpl.forLinkedNode(
elementFactory.analysisContext,
elementFactory.analysisSession,
node.name,
hasName ? node.nameOffset : -1,
node.name.length,
definingUnitContext,
reference,
definingUnitData.node,
);
var units = <CompilationUnitElementImpl>[];
var unitContainerRef = reference.getChild('@unit');
for (var unitData in node.units) {
var unitSource = sourceFactory.forUri(unitData.uriStr);
var tokensContext = TokensContext(unitData.tokens);
var unitElement = CompilationUnitElementImpl.forLinkedNode(
libraryElement,
LinkedUnitContext(libraryData.context, tokensContext),
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;
}
Element _function(CompilationUnitElementImpl enclosing, Reference reference) {
enclosing.functions;
assert(reference.element != null);
return reference.element;
}
PropertyAccessorElementImpl _getter(
ElementImpl enclosing, Reference reference) {
if (enclosing is ClassElementImpl) {
enclosing.accessors;
// Requesting accessors sets elements for accessors and fields.
assert(reference.element != null);
return reference.element;
}
if (enclosing is CompilationUnitElementImpl) {
enclosing.accessors;
// Requesting accessors sets elements for accessors and variables.
assert(reference.element != null);
return reference.element;
}
// Only classes and units have accessors.
throw StateError('${enclosing.runtimeType}');
}
void _indexUnitDeclarations(CompilationUnitElementImpl unit) {
var context = unit.linkedContext;
var unitRef = unit.reference;
var classRef = unitRef.getChild('@class');
var enumRef = unitRef.getChild('@class');
var functionRef = unitRef.getChild('@function');
var typeAliasRef = unitRef.getChild('@typeAlias');
var variableRef = unitRef.getChild('@variable');
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 if (kind == LinkedNodeKind.enumDeclaration) {
var name = context.getUnitMemberName(declaration);
enumRef.getChild(name).node = declaration;
} else if (kind == LinkedNodeKind.functionDeclaration) {
var name = context.getUnitMemberName(declaration);
functionRef.getChild(name).node = declaration;
} else if (kind == LinkedNodeKind.functionTypeAlias) {
var name = context.getUnitMemberName(declaration);
typeAliasRef.getChild(name).node = declaration;
} else if (kind == LinkedNodeKind.topLevelVariableDeclaration) {
var variables = declaration.topLevelVariableDeclaration_variableList;
for (var variable in variables.variableDeclarationList_variables) {
var name = context.getSimpleName(variable.variableDeclaration_name);
variableRef.getChild(name).node = variable;
}
} else {
throw UnimplementedError('$kind');
}
}
}
MethodElementImpl _method(ClassElementImpl enclosing, Reference reference) {
enclosing.methods;
// Requesting methods sets elements for all of them.
assert(reference.element != null);
return reference.element;
}
Element _parameter(ExecutableElementImpl enclosing, Reference reference) {
enclosing.parameters;
assert(reference.element != null);
return reference.element;
}
GenericTypeAliasElementImpl _typeAlias(
CompilationUnitElementImpl unit, Reference reference) {
if (reference.node == null) {
_indexUnitDeclarations(unit);
assert(reference.node != 0, '$reference');
}
return reference.element = GenericTypeAliasElementImpl.forLinkedNode(
unit,
reference,
reference.node,
);
}
Element _typeParameter(
TypeParameterizedElement enclosing, Reference reference) {
enclosing.typeParameters;
// Requesting type parameters sets elements for all their references.
assert(reference.element != null);
return reference.element;
}
}
class _Library {
final LinkedBundleContext context;
final LinkedNodeLibrary node;
_Library(this.context, this.node);
}