blob: 630cb964378f8543598f2d292a15149ebe599fba [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/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary2/linked_element_factory.dart';
import 'package:analyzer/src/summary2/linking_bundle_context.dart';
import 'package:analyzer/src/summary2/reference.dart';
/// The context of a linked bundle, with shared references.
class LinkedBundleContext {
final LinkedElementFactory elementFactory;
final LinkedNodeReferences referencesData;
final List<Reference> _references;
/// If the bundle is being linked, the reference to the linking context.
/// Otherwise `null`, and we are not expected to access it.
LinkingBundleContext linking;
LinkedBundleContext(this.elementFactory, this.referencesData)
: _references = List<Reference>.filled(referencesData.name.length, null,
growable: true);
T elementOfIndex<T extends Element>(int index) {
var reference = referenceOfIndex(index);
return elementFactory.elementOfReference(reference);
}
List<T> elementsOfIndexes<T extends Element>(List<int> indexList) {
var result = List<T>(indexList.length);
for (var i = 0; i < indexList.length; ++i) {
var index = indexList[i];
result[i] = elementOfIndex(index);
}
return result;
}
InterfaceType getInterfaceType(LinkedNodeType linkedType) {
var type = getType(linkedType);
if (type is InterfaceType && !type.element.isEnum) {
return type;
}
return null;
}
DartType getType(LinkedNodeType linkedType) {
var kind = linkedType.kind;
if (kind == LinkedNodeTypeKind.dynamic_) {
return DynamicTypeImpl.instance;
} else if (kind == LinkedNodeTypeKind.genericTypeAlias) {
var reference = referenceOfIndex(linkedType.genericTypeAliasReference);
return GenericTypeAliasElementImpl.typeAfterSubstitution(
elementFactory.elementOfReference(reference),
linkedType.genericTypeAliasTypeArguments.map(getType).toList(),
);
} else if (kind == LinkedNodeTypeKind.function) {
var returnType = getType(linkedType.functionReturnType);
var formalParameters = linkedType.functionFormalParameters.map((p) {
return ParameterElementImpl.synthetic(
p.name,
getType(p.type),
_formalParameterKind(p.kind),
);
}).toList();
return FunctionElementImpl.synthetic(formalParameters, returnType).type;
} else if (kind == LinkedNodeTypeKind.interface) {
var reference = referenceOfIndex(linkedType.interfaceClass);
Element element = elementFactory.elementOfReference(reference);
return InterfaceTypeImpl.explicit(
element,
linkedType.interfaceTypeArguments.map(getType).toList(),
);
} else if (kind == LinkedNodeTypeKind.typeParameter) {
var reference = referenceOfIndex(linkedType.typeParameterParameter);
Element element = elementFactory.elementOfReference(reference);
return TypeParameterTypeImpl(element);
} else if (kind == LinkedNodeTypeKind.void_) {
return VoidTypeImpl.instance;
} else {
throw UnimplementedError('$kind');
}
}
Reference referenceOfIndex(int index) {
// When we are linking a bundle, we add new references.
// So, grow the list of references when we have data for them.
if (index >= _references.length) {
if (referencesData.name.length > _references.length) {
_references.length = referencesData.name.length;
}
}
var reference = _references[index];
if (reference != null) return reference;
if (index == 0) {
reference = elementFactory.rootReference;
_references[index] = reference;
return reference;
}
var parentIndex = referencesData.parent[index];
var parent = referenceOfIndex(parentIndex);
var name = referencesData.name[index];
reference = parent.getChild(name);
_references[index] = reference;
return reference;
}
ParameterKind _formalParameterKind(LinkedNodeFormalParameterKind kind) {
if (kind == LinkedNodeFormalParameterKind.optionalNamed) {
return ParameterKind.NAMED;
}
if (kind == LinkedNodeFormalParameterKind.optionalPositional) {
return ParameterKind.POSITIONAL;
}
return ParameterKind.REQUIRED;
}
}