blob: 43cb699b70a596c3cb3e5b8c306d5721e177edc6 [file] [log] [blame]
// Copyright (c) 2017, 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/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/context/context.dart' show AnalysisContextImpl;
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/handle.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
import 'package:analyzer/src/summary/summary_sdk.dart';
import 'package:front_end/src/base/resolve_relative_uri.dart';
import 'package:front_end/src/base/source.dart';
import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart' as kernel;
import 'package:front_end/src/fasta/kernel/redirecting_factory_body.dart';
import 'package:kernel/kernel.dart' as kernel;
import 'package:kernel/type_algebra.dart' as kernel;
import 'package:kernel/type_environment.dart' as kernel;
import 'package:path/path.dart' as pathos;
/**
* Object that can resynthesize analyzer [LibraryElement] from Kernel.
*/
class KernelResynthesizer implements ElementResynthesizer {
final AnalysisContextImpl _analysisContext;
final kernel.TypeEnvironment _types;
final Map<String, kernel.Library> _kernelMap;
final Map<String, bool> _libraryExistMap;
final Map<String, LibraryElementImpl> _libraryMap = {};
/**
* Cache of [Source] objects that have already been converted from URIs.
*/
final Map<String, Source> _sources = <String, Source>{};
/// The type provider for this resynthesizer.
SummaryTypeProvider _typeProvider;
KernelResynthesizer(this._analysisContext, this._types, this._kernelMap,
this._libraryExistMap) {
_buildTypeProvider();
_analysisContext.typeProvider = _typeProvider;
}
@override
AnalysisContext get context => _analysisContext;
/**
* Return `true` if strong mode analysis should be used.
*/
bool get strongMode => _analysisContext.analysisOptions.strongMode;
/**
* Return the `Type` type.
*/
DartType get typeType => getLibrary('dart:core').getType('Type').type;
@override
Element getElement(ElementLocation location) {
List<String> components = location.components;
LibraryElementImpl library = getLibrary(components[0]);
if (components.length == 1) {
return library;
}
CompilationUnitElement unit;
for (var libraryUnit in library.units) {
if (libraryUnit.source.uri.toString() == components[1]) {
unit = libraryUnit;
break;
}
}
if (unit == null) {
throw new ArgumentError('Unable to find unit: $location');
}
if (components.length == 2) {
return unit;
}
ElementImpl element = unit as ElementImpl;
for (int i = 2; i < components.length; i++) {
if (element == null) {
throw new ArgumentError('Unable to find element: $location');
}
element = element.getChild(components[i]);
}
return element;
}
/**
* Return the [ElementImpl] that corresponds to the given [name], or `null`
* if the corresponding element cannot be found.
*/
ElementImpl getElementFromCanonicalName(kernel.CanonicalName name) {
if (name == null) return null;
var components = new List<String>(5);
var componentPtr = 0;
for (var namePart = name;
namePart != null && !namePart.isRoot;
namePart = namePart.parent) {
components[componentPtr++] = namePart.name;
}
String libraryUri = components[--componentPtr];
String topKindOrClassName = components[--componentPtr];
LibraryElementImpl library = getLibrary(libraryUri);
if (library == null) return null;
String takeElementName() {
String publicNameOrLibraryUri = components[--componentPtr];
if (publicNameOrLibraryUri == libraryUri) {
return components[--componentPtr];
} else {
return publicNameOrLibraryUri;
}
}
// Top-level element other than class.
if (topKindOrClassName == '@fields' ||
topKindOrClassName == '@methods' ||
topKindOrClassName == '@getters' ||
topKindOrClassName == '@setters' ||
topKindOrClassName == '@typedefs') {
String elementName = takeElementName();
for (CompilationUnitElement unit in library.units) {
CompilationUnitElementImpl unitImpl = unit;
ElementImpl child = unitImpl.getChild(elementName);
if (child != null) {
return child;
}
}
return null;
}
AbstractClassElementImpl classElement;
for (CompilationUnitElement unit in library.units) {
CompilationUnitElementImpl unitImpl = unit;
classElement = unitImpl.getChild(topKindOrClassName);
if (classElement != null) {
break;
}
}
if (classElement == null) return null;
// If no more component, the class is the element.
if (componentPtr == 0) return classElement;
String kind = components[--componentPtr];
String elementName = takeElementName();
if (kind == '@methods') {
return classElement.getMethod(elementName) as ElementImpl;
} else if (kind == '@getters') {
return classElement.getGetter(elementName) as ElementImpl;
} else if (kind == '@setters') {
return classElement.getSetter(elementName) as ElementImpl;
} else if (kind == '@fields') {
return classElement.getField(elementName) as ElementImpl;
} else if (kind == '@constructors' || kind == '@factories') {
if (elementName.isEmpty) {
return classElement.unnamedConstructor as ElementImpl;
}
return classElement.getNamedConstructor(elementName) as ElementImpl;
} else {
throw new UnimplementedError('Internal error: $kind unexpected.');
}
}
/**
* Return the [LibraryElementImpl] for the given [uriStr], or `null` if
* the library is not part of the Kernel libraries bundle.
*/
LibraryElementImpl getLibrary(String uriStr) {
return _libraryMap.putIfAbsent(uriStr, () {
var kernel = _kernelMap[uriStr];
if (kernel == null) return null;
if (_libraryExistMap[uriStr] != true) {
return _newSyntheticLibrary(uriStr);
}
var libraryContext =
new _KernelLibraryResynthesizerContextImpl(this, kernel);
// Build the library.
LibraryElementImpl libraryElement = libraryContext._buildLibrary(uriStr);
if (libraryElement == null) return null;
// Build the defining unit.
var definingUnit = libraryContext._buildUnit(null).unit;
libraryElement.definingCompilationUnit = definingUnit;
// Build units for parts.
var parts = new List<CompilationUnitElementImpl>(kernel.parts.length);
for (int i = 0; i < kernel.parts.length; i++) {
var fileUri = kernel.fileUri.resolve(kernel.parts[i].partUri);
var unitContext = libraryContext._buildUnit("$fileUri");
parts[i] = unitContext.unit;
}
libraryElement.parts = parts;
// Create the required `loadLibrary` function.
if (uriStr != 'dart:core' && uriStr != 'dart:async') {
libraryElement.createLoadLibraryFunction(_typeProvider);
}
return libraryElement;
});
}
DartType getType(ElementImpl context, kernel.DartType kernelType) {
if (kernelType is kernel.DynamicType) return DynamicTypeImpl.instance;
if (kernelType is kernel.InvalidType) return UndefinedTypeImpl.instance;
if (kernelType is kernel.BottomType) return BottomTypeImpl.instance;
if (kernelType is kernel.VoidType) return VoidTypeImpl.instance;
if (kernelType is kernel.InterfaceType) {
var name = kernelType.className.canonicalName;
if (!strongMode &&
name.name == 'FutureOr' &&
name.parent.name == 'dart:async') {
return DynamicTypeImpl.instance;
}
return _getInterfaceType(context, name, kernelType.typeArguments);
}
if (kernelType is kernel.TypeParameterType) {
kernel.TypeParameter kTypeParameter = kernelType.parameter;
return _getTypeParameter(context, kTypeParameter).type;
}
if (kernelType is kernel.FunctionType) {
return _getFunctionType(context, kernelType);
}
// TODO(scheglov) Support other kernel types.
throw new UnimplementedError('For ${kernelType.runtimeType}');
}
void _buildTypeProvider() {
var coreLibrary = getLibrary('dart:core');
var asyncLibrary = getLibrary('dart:async');
_typeProvider = new SummaryTypeProvider();
_typeProvider.initializeCore(coreLibrary);
_typeProvider.initializeAsync(asyncLibrary);
// Now, when TypeProvider is ready, we can finalize core/async.
coreLibrary.createLoadLibraryFunction(_typeProvider);
asyncLibrary.createLoadLibraryFunction(_typeProvider);
}
/// Return the [FunctionType] that corresponds to the given [kernelType].
FunctionType _getFunctionType(
ElementImpl context, kernel.FunctionType kernelType) {
if (kernelType.typedef != null) {
return _getTypedefType(context, kernelType);
}
var element = new FunctionElementImpl('', -1);
context.encloseElement(element);
// Set type parameters.
{
List<kernel.TypeParameter> typeParameters = kernelType.typeParameters;
int count = typeParameters.length;
var astTypeParameters = new List<TypeParameterElement>(count);
for (int i = 0; i < count; i++) {
astTypeParameters[i] =
new TypeParameterElementImpl.forKernel(element, typeParameters[i]);
}
element.typeParameters = astTypeParameters;
}
// Set formal parameters.
var parameters = _getFunctionTypeParameters(kernelType);
var positionalParameters = parameters[0];
var namedParameters = parameters[1];
var astParameters = ParameterElementImpl.forKernelParameters(
element,
kernelType.requiredParameterCount,
positionalParameters,
namedParameters);
element.parameters = astParameters;
element.returnType = getType(element, kernelType.returnType);
return new FunctionTypeImpl(element);
}
InterfaceType _getInterfaceType(ElementImpl context,
kernel.CanonicalName className, List<kernel.DartType> kernelArguments) {
var libraryName = className.parent;
var libraryElement = getLibrary(libraryName.name);
ClassElement classElement = libraryElement.getType(className.name);
classElement ??= libraryElement.getEnum(className.name);
if (kernelArguments.isEmpty) {
return classElement.type;
}
return new InterfaceTypeImpl.elementWithNameAndArgs(
classElement, classElement.name, () {
List<DartType> arguments = kernelArguments
.map((kernel.DartType k) => getType(context, k))
.toList(growable: false);
return arguments;
});
}
/**
* Get the [Source] object for the given [uri].
*/
Source _getSource(String uri) {
return _sources.putIfAbsent(
uri, () => _analysisContext.sourceFactory.forUri(uri));
}
/// Return the [FunctionType] for the given typedef based [kernelType].
FunctionType _getTypedefType(
ElementImpl context, kernel.FunctionType kernelType) {
kernel.Typedef typedef = kernelType.typedef;
GenericTypeAliasElementImpl typedefElement =
getElementFromCanonicalName(typedef.canonicalName);
GenericFunctionTypeElementImpl functionElement = typedefElement.function;
kernel.FunctionType typedefType = typedef.type;
var kernelTypeParameters = typedef.typeParameters.toList();
kernelTypeParameters.addAll(typedefType.typeParameters);
// If no type parameters, the raw type of the element will do.
FunctionTypeImpl rawType = functionElement.type;
if (kernelTypeParameters.isEmpty) {
return rawType;
}
// Compute type arguments for kernel type parameters.
var kernelMap = kernel.unifyTypes(typedefType.withoutTypeParameters,
kernelType.withoutTypeParameters, kernelTypeParameters.toSet());
// Prepare Analyzer type parameters, in the same order as kernel ones.
var astTypeParameters = typedefElement.typeParameters.toList();
astTypeParameters.addAll(functionElement.typeParameters);
// Convert kernel type arguments into Analyzer types.
int length = astTypeParameters.length;
var usedTypeParameters = <TypeParameterElement>[];
var usedTypeArguments = <DartType>[];
for (var i = 0; i < length; i++) {
var kernelParameter = kernelTypeParameters[i];
var kernelArgument = kernelMap[kernelParameter];
if (kernelArgument == null ||
kernelArgument is kernel.TypeParameterType &&
kernelArgument.parameter.parent == null) {
continue;
}
TypeParameterElement astParameter = astTypeParameters[i];
DartType astArgument = getType(context, kernelArgument);
usedTypeParameters.add(astParameter);
usedTypeArguments.add(astArgument);
}
if (usedTypeParameters.isEmpty) {
return rawType;
}
// Replace Analyzer type parameters with type arguments.
throw new UnimplementedError('TODO(paulberry)');
}
/// Return the [TypeParameterElement] for the given [kernelTypeParameter].
TypeParameterElement _getTypeParameter(
ElementImpl context, kernel.TypeParameter kernelTypeParameter) {
String name = kernelTypeParameter.name;
for (var ctx = context; ctx != null; ctx = ctx.enclosingElement) {
if (ctx is TypeParameterizedElementMixin) {
for (var typeParameter in ctx.typeParameters) {
if (typeParameter.name == name) {
return typeParameter;
}
}
}
}
throw new StateError('Not found $kernelTypeParameter in $context');
}
LibraryElementImpl _newSyntheticLibrary(String uriStr) {
Source librarySource = _getSource(uriStr);
if (librarySource == null) return null;
LibraryElementImpl libraryElement =
new LibraryElementImpl(context, '', -1, 0);
libraryElement.isSynthetic = true;
CompilationUnitElementImpl unitElement =
new CompilationUnitElementImpl(librarySource.shortName);
libraryElement.definingCompilationUnit = unitElement;
unitElement.source = librarySource;
unitElement.librarySource = librarySource;
libraryElement.createLoadLibraryFunction(_typeProvider);
libraryElement.publicNamespace = new Namespace({});
libraryElement.exportNamespace = new Namespace({});
return libraryElement;
}
/// Return the list with exactly two elements - positional and named
/// parameter lists.
static List<List<kernel.VariableDeclaration>> _getFunctionTypeParameters(
kernel.FunctionType type) {
int positionalCount = type.positionalParameters.length;
var positionalParameters =
new List<kernel.VariableDeclaration>(positionalCount);
for (int i = 0; i < positionalCount; i++) {
String name = i < type.positionalParameterNames.length
? type.positionalParameterNames[i]
: 'arg_$i';
positionalParameters[i] = new kernel.VariableDeclaration(name,
type: type.positionalParameters[i]);
}
var namedParameters = type.namedParameters
.map((k) => new kernel.VariableDeclaration(k.name, type: k.type))
.toList(growable: false);
return [positionalParameters, namedParameters];
}
}
/**
* This exception is thrown when we detect that the Kernel has a compilation
* error, so we cannot resynthesize the constant expression.
*/
class _CompilationErrorFound {
const _CompilationErrorFound();
}
/**
* Builder of [Expression]s from [kernel.Expression]s.
*/
class _ExprBuilder {
final _KernelUnitResynthesizerContextImpl _context;
final ElementImpl _contextElement;
_ExprBuilder(this._context, this._contextElement);
Expression build(kernel.Expression expr) {
try {
return _build(expr);
} on _CompilationErrorFound {
return AstTestFactory.identifier3('#invalidConst');
}
}
ConstructorInitializer buildInitializer(kernel.Initializer k) {
if (k is kernel.FieldInitializer) {
Expression value = build(k.value);
ConstructorFieldInitializer initializer = AstTestFactory
.constructorFieldInitializer(false, k.field.name.name, value);
initializer.fieldName.staticElement = _getElement(k.fieldReference);
return initializer;
}
if (k is kernel.AssertInitializer) {
var body = k.statement;
var condition = build(body.condition);
var message = body.message != null ? build(body.message) : null;
return AstTestFactory.assertInitializer(condition, message);
}
if (k is kernel.RedirectingInitializer) {
ConstructorElementImpl redirect = _getElement(k.targetReference);
var arguments = _toArguments(k.arguments);
RedirectingConstructorInvocation invocation =
AstTestFactory.redirectingConstructorInvocation(arguments);
invocation.staticElement = redirect;
String name = k.target.name.name;
if (name.isNotEmpty) {
invocation.constructorName = AstTestFactory.identifier3(name)
..staticElement = redirect;
}
return invocation;
}
if (k is kernel.SuperInitializer) {
ConstructorElementImpl redirect = _getElement(k.targetReference);
var arguments = _toArguments(k.arguments);
SuperConstructorInvocation invocation =
AstTestFactory.superConstructorInvocation(arguments);
invocation.staticElement = redirect;
String name = k.target.name.name;
if (name.isNotEmpty) {
invocation.constructorName = AstTestFactory.identifier3(name)
..staticElement = redirect;
}
return invocation;
}
if (k is kernel.ShadowInvalidInitializer) {
return null;
}
throw new UnimplementedError('For ${k.runtimeType}');
}
Expression _build(kernel.Expression expr) {
if (expr is kernel.NullLiteral) {
return AstTestFactory.nullLiteral();
}
if (expr is kernel.BoolLiteral) {
return AstTestFactory.booleanLiteral(expr.value);
}
if (expr is kernel.IntLiteral) {
return AstTestFactory.integer(expr.value);
}
if (expr is kernel.DoubleLiteral) {
return AstTestFactory.doubleLiteral(expr.value);
}
if (expr is kernel.StringLiteral) {
return AstTestFactory.string2(expr.value);
}
if (expr is kernel.StringConcatenation) {
List<InterpolationElement> elements = expr.expressions
.map(_build)
.map(_newInterpolationElement)
.toList(growable: false);
return AstTestFactory.string(elements);
}
if (expr is kernel.SymbolLiteral) {
List<String> components = expr.value.split('.').toList();
return AstTestFactory.symbolLiteral(components);
}
if (expr is kernel.ListLiteral) {
Keyword keyword = expr.isConst ? Keyword.CONST : null;
var typeArguments = _buildTypeArgumentList([expr.typeArgument]);
var elements = expr.expressions.map(_build).toList();
return AstTestFactory.listLiteral2(keyword, typeArguments, elements);
}
if (expr is kernel.MapLiteral) {
Keyword keyword = expr.isConst ? Keyword.CONST : null;
var typeArguments =
_buildTypeArgumentList([expr.keyType, expr.valueType]);
int numberOfEntries = expr.entries.length;
var entries = new List<MapLiteralEntry>(numberOfEntries);
for (int i = 0; i < numberOfEntries; i++) {
var entry = expr.entries[i];
Expression key = _build(entry.key);
Expression value = _build(entry.value);
entries[i] = AstTestFactory.mapLiteralEntry2(key, value);
}
return AstTestFactory.mapLiteral(keyword, typeArguments, entries);
}
// Invalid annotations are represented as Let.
if (expr is kernel.Let) {
kernel.Let let = expr;
if (_isStaticError(let.variable.initializer) ||
_isStaticError(let.body)) {
throw const _CompilationErrorFound();
}
}
// Stop if there is an error.
if (_isStaticError(expr)) {
throw const _CompilationErrorFound();
}
if (expr is kernel.StaticGet) {
return _buildIdentifier(expr.targetReference, isGet: true);
}
if (expr is kernel.ThisExpression) {
return AstTestFactory.thisExpression();
}
if (expr is kernel.PropertyGet) {
Expression target = _build(expr.receiver);
kernel.Reference reference = expr.interfaceTargetReference;
SimpleIdentifier identifier = _buildSimpleIdentifier(reference);
return AstTestFactory.propertyAccess(target, identifier);
}
if (expr is kernel.VariableGet) {
String name = expr.variable.name;
Element contextConstructor = _contextElement;
if (contextConstructor is ConstructorElement) {
SimpleIdentifier identifier = AstTestFactory.identifier3(name);
ParameterElement parameter = contextConstructor.parameters.firstWhere(
(parameter) => parameter.name == name,
orElse: () => null);
identifier.staticElement = parameter;
return identifier;
}
}
if (expr is kernel.ConditionalExpression) {
var condition = _build(expr.condition);
var then = _build(expr.then);
var otherwise = _build(expr.otherwise);
return AstTestFactory.conditionalExpression(condition, then, otherwise);
}
if (expr is kernel.Not) {
kernel.Expression kernelOperand = expr.operand;
var operand = _build(kernelOperand);
return AstTestFactory.prefixExpression(TokenType.BANG, operand);
}
if (expr is kernel.LogicalExpression) {
var operator = _toBinaryOperatorTokenType(expr.operator);
var left = _build(expr.left);
var right = _build(expr.right);
return AstTestFactory.binaryExpression(left, operator, right);
}
if (expr is kernel.AsExpression && expr.isTypeError) {
return _build(expr.operand);
}
if (expr is kernel.Let) {
var body = expr.body;
if (body is kernel.ConditionalExpression) {
var condition = body.condition;
var otherwiseExpr = body.otherwise;
if (condition is kernel.MethodInvocation) {
var equalsReceiver = condition.receiver;
if (equalsReceiver is kernel.VariableGet &&
condition.name.name == '==' &&
condition.arguments.positional.length == 1 &&
condition.arguments.positional[0] is kernel.NullLiteral &&
otherwiseExpr is kernel.VariableGet &&
otherwiseExpr.variable == equalsReceiver.variable) {
var left = _build(expr.variable.initializer);
var right = _build(body.then);
return AstTestFactory.binaryExpression(
left, TokenType.QUESTION_QUESTION, right);
}
}
}
}
if (expr is kernel.MethodInvocation) {
var left = _build(expr.receiver);
String operatorName = expr.name.name;
List<kernel.Expression> args = expr.arguments.positional;
if (args.isEmpty) {
if (operatorName == 'unary-') {
return AstTestFactory.prefixExpression(TokenType.MINUS, left);
}
if (operatorName == '~') {
return AstTestFactory.prefixExpression(TokenType.TILDE, left);
}
} else if (args.length == 1) {
var operator = _toBinaryOperatorTokenType(operatorName);
var right = _build(args.single);
return AstTestFactory.binaryExpression(left, operator, right);
}
}
if (expr is kernel.StaticInvocation) {
kernel.Procedure target = expr.target;
String name = target.name.name;
List<Expression> arguments = _toArguments(expr.arguments);
MethodInvocation invocation =
AstTestFactory.methodInvocation3(null, name, null, arguments);
invocation.methodName.staticElement = _getElement(target.reference);
return invocation;
}
if (expr is kernel.ConstructorInvocation) {
var element = _getElement(expr.targetReference);
var kernelType =
expr.getStaticType(_context.libraryContext.resynthesizer._types);
var type = _context.getType(_contextElement, kernelType);
TypeName typeName = _buildType(type);
var constructorName = AstTestFactory.constructorName(
typeName, element.name.isNotEmpty ? element.name : null);
constructorName?.name?.staticElement = element;
var keyword = expr.isConst ? Keyword.CONST : Keyword.NEW;
var arguments = _toArguments(expr.arguments);
return AstTestFactory.instanceCreationExpression(
keyword, constructorName, arguments);
}
if (expr is kernel.TypeLiteral) {
ElementImpl element;
var kernelType = expr.type;
if (kernelType is kernel.FunctionType) {
element = _getElement(kernelType.typedefReference);
} else {
var type = _context.getType(_contextElement, kernelType);
element = type.element;
}
var identifier = AstTestFactory.identifier3(element.name);
identifier.staticElement = element;
identifier.staticType = _context.libraryContext.resynthesizer.typeType;
return identifier;
}
// TODO(scheglov): complete getExpression
throw new UnimplementedError('kernel: (${expr.runtimeType}) $expr');
}
Identifier _buildIdentifier(kernel.Reference reference, {bool isGet: false}) {
Element element = _getElement(reference);
if (isGet && element is PropertyInducingElement) {
element = (element as PropertyInducingElement).getter;
}
SimpleIdentifier property = AstTestFactory.identifier3(element.displayName)
..staticElement = element;
Element enclosingElement = element.enclosingElement;
if (enclosingElement is ClassElement) {
SimpleIdentifier classRef = AstTestFactory
.identifier3(enclosingElement.name)
..staticElement = enclosingElement;
return AstTestFactory.identifier(classRef, property);
} else {
return property;
}
}
SimpleIdentifier _buildSimpleIdentifier(kernel.Reference reference) {
if (reference == null) {
throw const _CompilationErrorFound();
}
String name = reference.canonicalName.name;
SimpleIdentifier identifier = AstTestFactory.identifier3(name);
Element element = _getElement(reference);
identifier.staticElement = element;
return identifier;
}
TypeAnnotation _buildType(DartType type) {
List<TypeAnnotation> argumentNodes;
if (type is ParameterizedType) {
argumentNodes = _buildTypeArguments(type.typeArguments);
}
TypeName node = AstTestFactory.typeName4(type.name, argumentNodes);
node.type = type;
(node.name as SimpleIdentifier).staticElement = type.element;
return node;
}
TypeArgumentList _buildTypeArgumentList(List<kernel.DartType> kernels) {
int length = kernels.length;
var types = new List<TypeAnnotation>(length);
for (int i = 0; i < length; i++) {
DartType type = _context.getType(_contextElement, kernels[i]);
TypeAnnotation typeAnnotation = _buildType(type);
types[i] = typeAnnotation;
}
return AstTestFactory.typeArgumentList(types);
}
List<TypeAnnotation> _buildTypeArguments(List<DartType> types) {
if (types.every((t) => t.isDynamic)) return null;
return types.map(_buildType).toList();
}
ElementImpl _getElement(kernel.Reference reference) {
return _context.libraryContext.resynthesizer
.getElementFromCanonicalName(reference?.canonicalName);
}
InterpolationElement _newInterpolationElement(Expression expr) {
if (expr is SimpleStringLiteral) {
return astFactory.interpolationString(expr.literal, expr.value);
} else {
return AstTestFactory.interpolationExpression(expr);
}
}
/// Return [Expression]s for the given [kernelArguments].
List<Expression> _toArguments(kernel.Arguments kernelArguments) {
int numPositional = kernelArguments.positional.length;
int numNamed = kernelArguments.named.length;
var arguments = new List<Expression>(numPositional + numNamed);
int i = 0;
for (kernel.Expression k in kernelArguments.positional) {
arguments[i++] = _build(k);
}
for (kernel.NamedExpression k in kernelArguments.named) {
var value = _build(k.value);
arguments[i++] = AstTestFactory.namedExpression2(k.name, value);
}
return arguments;
}
/// Return the [TokenType] for the given operator [name].
TokenType _toBinaryOperatorTokenType(String name) {
if (name == '==') return TokenType.EQ_EQ;
if (name == '&&') return TokenType.AMPERSAND_AMPERSAND;
if (name == '||') return TokenType.BAR_BAR;
if (name == '^') return TokenType.CARET;
if (name == '&') return TokenType.AMPERSAND;
if (name == '|') return TokenType.BAR;
if (name == '>>') return TokenType.GT_GT;
if (name == '<<') return TokenType.LT_LT;
if (name == '+') return TokenType.PLUS;
if (name == '-') return TokenType.MINUS;
if (name == '*') return TokenType.STAR;
if (name == '/') return TokenType.SLASH;
if (name == '~/') return TokenType.TILDE_SLASH;
if (name == '%') return TokenType.PERCENT;
if (name == '>') return TokenType.GT;
if (name == '<') return TokenType.LT;
if (name == '>=') return TokenType.GT_EQ;
if (name == '<=') return TokenType.LT_EQ;
if (name == 'unary-') return TokenType.MINUS;
throw new ArgumentError(name);
}
/**
* Return `true` if the given [expr] throws an instance of
* `_ConstantExpressionError` defined in `dart:core`.
*/
static bool _isStaticError(kernel.Expression expr) {
return expr is kernel.InvalidExpression;
}
}
/**
* Implementation of [KernelLibraryResynthesizerContext].
*/
class _KernelLibraryResynthesizerContextImpl
implements KernelLibraryResynthesizerContext {
final KernelResynthesizer resynthesizer;
@override
final kernel.Library library;
/**
* The relative URI of the directory with the [library] file.
* E.g. `sdk/lib/core` for `sdk/lib/core/core.dart`.
*/
String libraryDirectoryUri;
Source librarySource;
LibraryElementImpl libraryElement;
_KernelLibraryResynthesizerContextImpl(this.resynthesizer, this.library) {
libraryDirectoryUri = pathos.url.dirname("${library.fileUri}");
}
@override
kernel.Library get coreLibrary => resynthesizer._kernelMap['dart:core'];
@override
bool get hasExtUri {
for (var dependency in library.dependencies) {
if (dependency.isImport &&
dependency.targetLibrary.importUri.isScheme('dart-ext')) {
return true;
}
}
return false;
}
@override
Namespace buildExportNamespace() {
Namespace publicNamespace = buildPublicNamespace();
if (library.additionalExports.isEmpty) {
return publicNamespace;
}
Map<String, Element> definedNames = publicNamespace.definedNames;
for (kernel.Reference additionalExport in library.additionalExports) {
var element = resynthesizer
.getElementFromCanonicalName(additionalExport.canonicalName);
if (element != null) {
definedNames[element.name] = element;
}
}
return new Namespace(definedNames);
}
@override
Namespace buildPublicNamespace() {
return new NamespaceBuilder()
.createPublicNamespaceForLibrary(libraryElement);
}
@override
LibraryElementImpl getLibrary(String uriStr) {
return resynthesizer.getLibrary(uriStr);
}
LibraryElementImpl _buildLibrary(String uriStr) {
librarySource = resynthesizer._getSource(uriStr);
if (librarySource == null) return null;
return libraryElement =
new LibraryElementImpl.forKernel(resynthesizer._analysisContext, this);
}
_KernelUnitResynthesizerContextImpl _buildUnit(String fileUri) {
var unitContext = new _KernelUnitResynthesizerContextImpl(
this, fileUri ?? "${library.fileUri}");
var unitElement = new CompilationUnitElementImpl.forKernel(
libraryElement, unitContext, '<no name>');
unitContext.unit = unitElement;
unitElement.librarySource = librarySource;
if (fileUri != null) {
String absoluteUriStr;
if (fileUri.startsWith('file://')) {
// Compute the URI relative to the library directory.
// E.g. when the library directory URI is `sdk/lib/core`, and the unit
// URI is `sdk/lib/core/bool.dart`, the result is `bool.dart`.
var relativeUri =
pathos.url.relative(fileUri, from: libraryDirectoryUri);
// Compute the absolute URI.
// When the absolute library URI is `dart:core`, and the relative
// URI is `bool.dart`, the result is `dart:core/bool.dart`.
Uri absoluteUri =
resolveRelativeUri(librarySource.uri, Uri.parse(relativeUri));
absoluteUriStr = absoluteUri.toString();
} else {
// File URIs must have the "file" scheme.
// But for invalid URIs, which cannot be even parsed, FrontEnd returns
// URIs with the "org-dartlang-malformed-uri" scheme, and does not
// resolve them to file URIs.
// We don't have anything better than to use these URIs as is.
absoluteUriStr = fileUri;
}
unitElement.source = resynthesizer._getSource(absoluteUriStr);
} else {
unitElement.source = librarySource;
}
unitContext.unit = unitElement;
return unitContext;
}
}
/**
* Implementation of [KernelUnit].
*/
class _KernelUnitImpl implements KernelUnit {
final _KernelUnitResynthesizerContextImpl context;
List<kernel.Expression> _annotations;
List<kernel.Class> _classes;
List<kernel.Field> _fields;
List<kernel.Procedure> _procedures;
List<kernel.Typedef> _typedefs;
_KernelUnitImpl(this.context);
@override
List<kernel.Expression> get annotations {
if (_annotations == null) {
for (var part in context.libraryContext.library.parts) {
if ("${context.libraryContext.library.fileUri.resolve(part.partUri)}" ==
context.fileUri) {
return _annotations = part.annotations;
}
}
}
return _annotations ?? const <kernel.Expression>[];
}
@override
List<kernel.Class> get classes =>
_classes ??= context.libraryContext.library.classes
.where((n) => "${n.fileUri}" == context.fileUri)
.toList(growable: false);
@override
List<kernel.Field> get fields =>
_fields ??= context.libraryContext.library.fields
.where((n) => "${n.fileUri}" == context.fileUri)
.toList(growable: false);
@override
List<kernel.Procedure> get procedures =>
_procedures ??= context.libraryContext.library.procedures
.where((n) => "${n.fileUri}" == context.fileUri)
.toList(growable: false);
@override
List<kernel.Typedef> get typedefs =>
_typedefs ??= context.libraryContext.library.typedefs
.where((n) => "${n.fileUri}" == context.fileUri)
.toList(growable: false);
}
/**
* Implementation of [KernelUnitResynthesizerContext].
*/
class _KernelUnitResynthesizerContextImpl
implements KernelUnitResynthesizerContext {
static final Uri dartInternalUri = Uri.parse('dart:_internal');
final _KernelLibraryResynthesizerContextImpl libraryContext;
final String fileUri;
CompilationUnitElementImpl unit;
_KernelUnitResynthesizerContextImpl(this.libraryContext, this.fileUri);
@override
KernelUnit get kernelUnit => new _KernelUnitImpl(this);
@override
List<ElementAnnotation> buildAnnotations(
List<kernel.Expression> expressions) {
int length = expressions.length;
if (length != 0) {
var annotations = <ElementAnnotation>[];
for (var expression in expressions) {
if (_isSyntheticExternalNameAnnotation(expression)) continue;
var annotation = _buildAnnotation(unit, expression);
annotations.add(annotation);
}
return annotations;
} else {
return const <ElementAnnotation>[];
}
}
@override
UnitExplicitTopLevelAccessors buildTopLevelAccessors() {
var accessorsData = new UnitExplicitTopLevelAccessors();
var implicitVariables = <String, TopLevelVariableElementImpl>{};
// Build explicit property accessors and implicit fields.
for (var procedure in kernelUnit.procedures) {
bool isGetter = procedure.kind == kernel.ProcedureKind.Getter;
bool isSetter = procedure.kind == kernel.ProcedureKind.Setter;
if (isGetter || isSetter) {
var accessor =
new PropertyAccessorElementImpl.forKernel(unit, procedure);
accessorsData.accessors.add(accessor);
// Create or update the implicit variable.
String name = accessor.displayName;
TopLevelVariableElementImpl variable = implicitVariables[name];
if (variable == null) {
variable = new TopLevelVariableElementImpl(name, -1);
implicitVariables[name] = variable;
variable.enclosingElement = unit;
variable.isSynthetic = true;
variable.isFinal = isGetter;
} else {
variable.isFinal = false;
}
// Attach the accessor to the variable.
accessor.variable = variable;
if (isGetter) {
variable.getter = accessor;
} else {
variable.setter = accessor;
}
}
}
accessorsData.implicitVariables.addAll(implicitVariables.values);
return accessorsData;
}
@override
UnitExplicitTopLevelVariables buildTopLevelVariables() {
List<kernel.Field> kernelFields = kernelUnit.fields;
int numberOfVariables = kernelFields.length;
var variablesData = new UnitExplicitTopLevelVariables(numberOfVariables);
for (int i = 0; i < numberOfVariables; i++) {
kernel.Field field = kernelFields[i];
// Add the explicit variables.
TopLevelVariableElementImpl variable;
if (field.isConst && field.initializer != null) {
variable = new ConstTopLevelVariableElementImpl.forKernel(unit, field);
} else {
variable = new TopLevelVariableElementImpl.forKernel(unit, field);
}
variablesData.variables[i] = variable;
// Add the implicit accessors.
variablesData.implicitAccessors
.add(new PropertyAccessorElementImpl_ImplicitGetter(variable));
if (!(variable.isConst || variable.isFinal)) {
variablesData.implicitAccessors
.add(new PropertyAccessorElementImpl_ImplicitSetter(variable));
}
}
return variablesData;
}
@override
ConstructorInitializer getConstructorInitializer(
ConstructorElementImpl constructor, kernel.Initializer k) {
if (k is kernel.FieldInitializer && k.isSynthetic ||
k is kernel.SuperInitializer && k.isSynthetic) {
return null;
}
return new _ExprBuilder(this, constructor).buildInitializer(k);
}
@override
Expression getExpression(ElementImpl context, kernel.Expression expression) {
return new _ExprBuilder(this, context).build(expression);
}
@override
List<List<kernel.VariableDeclaration>> getFunctionTypeParameters(
kernel.FunctionType type) {
return KernelResynthesizer._getFunctionTypeParameters(type);
}
@override
InterfaceType getInterfaceType(
ElementImpl context, kernel.Supertype kernelType) {
if (kernelType.classNode.isEnum) {
return null;
}
return libraryContext.resynthesizer._getInterfaceType(
context, kernelType.className.canonicalName, kernelType.typeArguments);
}
@override
List<InterfaceType> getInterfaceTypes(
ElementImpl context, List<kernel.Supertype> types) {
var interfaceTypes = <InterfaceType>[];
for (kernel.Supertype kernelType in types) {
InterfaceType interfaceType = getInterfaceType(context, kernelType);
if (interfaceType != null) {
interfaceTypes.add(interfaceType);
}
}
return interfaceTypes;
}
@override
ConstructorElementImpl getRedirectedConstructor(
kernel.Constructor kernelConstructor, kernel.Procedure kernelFactory) {
if (kernelConstructor != null) {
for (var initializer in kernelConstructor.initializers) {
if (initializer is kernel.RedirectingInitializer) {
return libraryContext.resynthesizer.getElementFromCanonicalName(
initializer.targetReference.canonicalName)
as ConstructorElementImpl;
}
}
}
if (kernelFactory != null) {
kernel.Statement body = kernelFactory.function.body;
if (body is RedirectingFactoryBody) {
kernel.Member target = body.target;
if (target != null) {
return libraryContext.resynthesizer
.getElementFromCanonicalName(target.reference.canonicalName)
as ConstructorElementImpl;
}
}
}
return null;
}
@override
DartType getType(ElementImpl context, kernel.DartType type) {
return libraryContext.resynthesizer.getType(context, type);
}
ElementAnnotationImpl _buildAnnotation(
CompilationUnitElementImpl unit, kernel.Expression expression) {
ElementAnnotationImpl elementAnnotation = new ElementAnnotationImpl(unit);
Expression constExpr = getExpression(unit, expression);
if (constExpr is Identifier) {
elementAnnotation.element = constExpr.staticElement;
elementAnnotation.annotationAst = AstTestFactory.annotation(constExpr);
} else if (constExpr is InstanceCreationExpression) {
elementAnnotation.element = constExpr.staticElement;
Identifier typeName = constExpr.constructorName.type.name;
SimpleIdentifier constructorName = constExpr.constructorName.name;
elementAnnotation.annotationAst = AstTestFactory.annotation2(
typeName, constructorName, constExpr.argumentList)
..element = constExpr.staticElement;
} else {
throw new StateError(
'Unexpected annotation type: ${constExpr.runtimeType}');
}
return elementAnnotation;
}
/// Fasta converts `native 'name'` clauses to `@ExternalName('name')`
/// annotations. But we don't actually have these annotations in code. So,
/// we need to skip them to avoid mismatch with AST.
static bool _isSyntheticExternalNameAnnotation(kernel.Expression expr) {
if (expr is kernel.ConstructorInvocation) {
kernel.Constructor target = expr.target;
return target != null &&
target.enclosingClass.name == 'ExternalName' &&
target.enclosingLibrary.importUri == dartInternalUri;
}
return false;
}
}