blob: 144df5db4518fffb9281c45851a774ddc3193bcd [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/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary2/reference.dart';
class LinkingBundleContext {
/// The `dynamic` class is declared in `dart:core`, but is not a class.
/// Also, it is static, so we cannot set `reference` for it.
/// So, we have to push it in a separate way.
final Reference dynamicReference;
/// References used in all libraries being linked.
/// Element references in nodes are indexes in this list.
final List<Reference> references = [null];
/// Data about [references].
final LinkedNodeReferencesBuilder referencesBuilder =
LinkedNodeReferencesBuilder(
parent: [0],
name: [''],
);
final Map<TypeParameterElement, int> _typeParameters = Map.identity();
int _nextTypeParameterId = 1;
int _nextSyntheticTypeParameterId = 0x10000;
LinkingBundleContext(this.dynamicReference);
void addTypeParameter(TypeParameterElement element) {
_typeParameters[element] = _nextTypeParameterId++;
}
int idOfTypeParameter(TypeParameterElement element) {
return _typeParameters[element];
}
int indexOfElement(Element element) {
if (element == null) return 0;
assert(element is! Member);
if (identical(element, DynamicElementImpl.instance)) {
return indexOfReference(dynamicReference);
}
var reference = (element as ElementImpl).reference;
return indexOfReference(reference);
}
int indexOfReference(Reference reference) {
if (reference == null) return 0;
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;
}
LinkedNodeTypeBuilder writeType(DartType type) {
if (type == null) return null;
if (type.isBottom) {
return LinkedNodeTypeBuilder(
kind: LinkedNodeTypeKind.bottom,
);
} else if (type.isDynamic) {
return LinkedNodeTypeBuilder(
kind: LinkedNodeTypeKind.dynamic_,
);
} else if (type is FunctionType) {
return _writeFunctionType(type);
} else if (type is InterfaceType) {
return LinkedNodeTypeBuilder(
kind: LinkedNodeTypeKind.interface,
interfaceClass: indexOfElement(type.element),
interfaceTypeArguments: type.typeArguments.map(writeType).toList(),
);
} else if (type is TypeParameterType) {
TypeParameterElementImpl element = type.element;
return LinkedNodeTypeBuilder(
kind: LinkedNodeTypeKind.typeParameter,
typeParameterId: _typeParameters[element],
);
} else if (type is VoidType) {
return LinkedNodeTypeBuilder(
kind: LinkedNodeTypeKind.void_,
);
} else {
throw UnimplementedError('(${type.runtimeType}) $type');
}
}
LinkedNodeFormalParameterKind _formalParameterKind(ParameterElement p) {
// ignore: deprecated_member_use_from_same_package
var kind = p.parameterKind;
if (kind == ParameterKind.NAMED) {
return LinkedNodeFormalParameterKind.optionalNamed;
} else if (kind == ParameterKind.POSITIONAL) {
return LinkedNodeFormalParameterKind.optionalPositional;
} else if (kind == ParameterKind.NAMED_REQUIRED) {
return LinkedNodeFormalParameterKind.requiredNamed;
}
return LinkedNodeFormalParameterKind.requiredPositional;
}
FunctionType _toSyntheticFunctionType(FunctionType type) {
var typeParameters = type.typeFormals;
if (typeParameters.isEmpty) return type;
var onlySyntheticTypeParameters = typeParameters.every((e) {
return e is TypeParameterElementImpl && e.linkedNode == null;
});
if (onlySyntheticTypeParameters) return type;
var parameters = getFreshTypeParameters(typeParameters);
return parameters.applyToFunctionType(type);
}
LinkedNodeTypeBuilder _writeFunctionType(FunctionType type) {
type = _toSyntheticFunctionType(type);
var typeParameterBuilders = <LinkedNodeTypeTypeParameterBuilder>[];
var typeParameters = type.typeFormals;
for (var i = 0; i < typeParameters.length; ++i) {
var typeParameter = typeParameters[i];
_typeParameters[typeParameter] = _nextSyntheticTypeParameterId++;
typeParameterBuilders.add(
LinkedNodeTypeTypeParameterBuilder(name: typeParameter.name),
);
}
for (var i = 0; i < typeParameters.length; ++i) {
var typeParameter = typeParameters[i];
typeParameterBuilders[i].bound = writeType(typeParameter.bound);
}
var result = LinkedNodeTypeBuilder(
kind: LinkedNodeTypeKind.function,
functionFormalParameters: type.parameters
.map((p) => LinkedNodeTypeFormalParameterBuilder(
kind: _formalParameterKind(p),
name: p.name,
type: writeType(p.type),
))
.toList(),
functionReturnType: writeType(type.returnType),
functionTypeParameters: typeParameterBuilders,
);
for (var typeParameter in typeParameters) {
_typeParameters.remove(typeParameter);
--_nextSyntheticTypeParameterId;
}
return result;
}
}