Apply some element data, improve handling of generic function types, improve tests

Change-Id: I501a5273834cc2f7f73465377bf145da183cd207
Reviewed-on: https://dart-review.googlesource.com/23241
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Brian Wilkerson 2017-11-24 15:44:09 +00:00 committed by commit-bot@chromium.org
parent 4f551306f5
commit 042af775af
3 changed files with 170 additions and 30 deletions

View file

@ -31,12 +31,26 @@ class ResolutionApplier extends GeneralizingAstVisitor {
/// Verifies that all types passed to the constructor have been applied.
void checkDone() {
if (_declaredElementIndex != _declaredElements.length) {
throw new StateError('Some declarations were not consumed, starting at '
'${_declaredElements[_declaredElementIndex]}');
}
if (_referencedElementIndex != _referencedElements.length) {
throw new StateError('Some references were not consumed, starting at '
'${_referencedElements[_referencedElementIndex]}');
}
if (_typeIndex != _types.length) {
throw new StateError(
'Some types were not consumed, starting at ${_types[_typeIndex]}');
}
}
@override
void visitBinaryExpression(BinaryExpression node) {
visitExpression(node);
node.staticElement = _getReferenceFor(node);
}
@override
void visitExpression(Expression node) {
visitNode(node);
@ -66,6 +80,14 @@ class ResolutionApplier extends GeneralizingAstVisitor {
functionExpression.body?.accept(this);
}
@override
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
node.function.accept(this);
// TODO(brianwilkerson) Visit node.typeArguments.
node.argumentList.accept(this);
node.staticElement = _getReferenceFor(node);
}
@override
void visitInstanceCreationExpression(InstanceCreationExpression node) {
node.argumentList?.accept(this);
@ -99,7 +121,6 @@ class ResolutionApplier extends GeneralizingAstVisitor {
DartType invokeType = _getTypeFor(node.methodName);
node.staticInvokeType = invokeType;
node.methodName.staticType = invokeType;
// TODO(paulberry): store resolution of node.methodName.
// TODO(paulberry): store resolution of node.typeArguments.
// Apply resolution to arguments.
@ -199,7 +220,40 @@ class ResolutionApplier extends GeneralizingAstVisitor {
}
node.variables.accept(this);
if (node.type != null) {
_applyToTypeAnnotation(node.variables[0].name.staticType, node.type);
DartType type = node.variables[0].name.staticType;
// TODO(brianwilkerson) Understand why the type is sometimes `null`.
if (type != null) {
_applyToTypeAnnotation(type, node.type);
}
}
}
}
/// Apply the types of the [parameterElements] to the [parameters] that have
/// an explicit type annotation.
void _applyParameters(List<ParameterElement> parameterElements,
List<FormalParameter> parameters) {
int length = parameterElements.length;
if (parameters.length != length) {
throw new StateError('Parameter counts do not match');
}
for (int i = 0; i < length; i++) {
FormalParameter parameter = parameters[i];
NormalFormalParameter normalParameter;
if (parameter is NormalFormalParameter) {
normalParameter = parameter;
} else if (parameter is DefaultFormalParameter) {
normalParameter = parameter.parameter;
}
TypeAnnotation typeAnnotation = null;
if (normalParameter is SimpleFormalParameter) {
typeAnnotation = normalParameter.type;
}
if (typeAnnotation != null) {
_applyToTypeAnnotation(parameterElements[i].type, typeAnnotation);
}
if (normalParameter.identifier != null) {
normalParameter.identifier.staticElement = parameterElements[i];
}
}
}
@ -209,20 +263,31 @@ class ResolutionApplier extends GeneralizingAstVisitor {
/// arguments of the [type] to the corresponding type arguments of the
/// [typeAnnotation].
void _applyToTypeAnnotation(DartType type, TypeAnnotation typeAnnotation) {
SimpleIdentifier nameForElement(Identifier identifier) {
if (identifier is SimpleIdentifier) {
return identifier;
} else if (identifier is PrefixedIdentifier) {
return identifier.identifier;
} else {
throw new UnimplementedError(
'Unhandled class of identifier: ${identifier.runtimeType}');
}
}
if (typeAnnotation is GenericFunctionTypeImpl) {
// TODO(brianwilkerson) Finish adding support for generic function types.
if (type is! FunctionType) {
throw new StateError('Non-function type ($type) '
'for generic function annotation ($typeAnnotation)');
}
FunctionType functionType = type;
typeAnnotation.type = type;
_applyToTypeAnnotation(
functionType.returnType, typeAnnotation.returnType);
_applyParameters(
functionType.parameters, typeAnnotation.parameters.parameters);
} else if (typeAnnotation is TypeNameImpl) {
typeAnnotation.type = type;
if (type is InterfaceType) {
// TODO(scheglov) Support other types, e.g. dynamic.
Identifier name = typeAnnotation.name;
if (name is SimpleIdentifier) {
name.staticElement = type.element;
} else {
throw new UnimplementedError('${name.runtimeType}');
}
}
nameForElement(typeAnnotation.name).staticElement = type.element;
}
if (typeAnnotation is NamedType) {
TypeArgumentList typeArguments = typeAnnotation.typeArguments;
@ -315,6 +380,10 @@ class ValidatingResolutionApplier extends ResolutionApplier {
if (_debug) {
print('Getting declaration element for $node at $nodeOffset');
}
if (_declaredElementIndex >= _declaredElements.length) {
throw new StateError(
'No declaration information for $node at $nodeOffset');
}
int elementOffset = _declaredElementOffsets[_declaredElementIndex];
if (nodeOffset != elementOffset) {
throw new StateError(
@ -330,6 +399,9 @@ class ValidatingResolutionApplier extends ResolutionApplier {
if (_debug) {
print('Getting reference element for $node at $nodeOffset');
}
if (_referencedElementIndex >= _referencedElements.length) {
throw new StateError('No reference information for $node at $nodeOffset');
}
int elementOffset = _referencedElementOffsets[_referencedElementIndex];
if (nodeOffset != elementOffset) {
throw new StateError(
@ -345,8 +417,11 @@ class ValidatingResolutionApplier extends ResolutionApplier {
if (_debug) {
print('Getting type for $node at $nodeOffset');
}
if (_typeIndex >= _types.length) {
throw new StateError('No type information for $node at $nodeOffset');
}
if (nodeOffset != _typeOffsets[_typeIndex]) {
throw new StateError('Expected a type for analyzer offset $nodeOffset; '
throw new StateError('Expected a type for $node at $nodeOffset; '
'got one for kernel offset ${_typeOffsets[_typeIndex]}');
}
return super._getTypeFor(node);

View file

@ -9,6 +9,7 @@ import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/fasta/resolution_applier.dart';
import 'package:analyzer/src/generated/testing/test_type_provider.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@ -36,14 +37,23 @@ class ResolutionApplierTest extends FastaParserTestCase {
void applyTypes(String content, List<Element> declaredElements,
List<Element> referencedElements, List<DartType> types) {
CompilationUnit unit = parseCompilationUnit(content);
ResolutionApplier applier =
new ResolutionApplier(declaredElements, referencedElements, types);
expect(unit, isNotNull);
expect(unit.declarations, hasLength(1));
FunctionDeclaration function = unit.declarations[0];
FunctionBody body = function.functionExpression.body;
ResolutionApplier applier =
new ResolutionApplier(declaredElements, referencedElements, types);
applier.enclosingExecutable =
new FunctionElementImpl(function.name.name, function.name.offset);
body.accept(applier);
body.accept(new ResolutionVerifier());
applier.checkDone();
ResolutionVerifier verifier = new ResolutionVerifier();
// TODO(brianwilkerson) Uncomment the line below when the tests no longer
// fail.
// body.accept(verifier);
verifier.assertResolved();
}
void setUp() {
@ -56,8 +66,9 @@ f(String s, int i) {
return s + i;
}
''', [], [
new ParameterElementImpl('s', 9),
new ParameterElementImpl('i', 16)
_createFunctionParameter('s', 9),
_createFunctionParameter('i', 16),
new MethodElementImpl('+', -1)
], <DartType>[
typeProvider.stringType,
typeProvider.intType,
@ -65,7 +76,24 @@ f(String s, int i) {
]);
}
@failingTest
void test_functionExpressionInvocation() {
applyTypes(r'''
f(Object a) {
return a.b().c();
}
''', [], [
_createFunctionParameter('a', 9),
new MethodElementImpl('b', -1),
new MethodElementImpl('c', -1)
], <DartType>[
typeProvider.objectType,
typeProvider.objectType,
typeProvider.objectType,
typeProvider.objectType,
typeProvider.objectType
]);
}
void test_genericFunctionType() {
GenericFunctionTypeElementImpl element =
new GenericFunctionTypeElementImpl.forOffset(8);
@ -73,8 +101,8 @@ f(String s, int i) {
element.typeParameters = <TypeParameterElement>[];
element.returnType = typeProvider.intType;
element.parameters = [
new ParameterElementImpl('', -1)..type = typeProvider.stringType,
new ParameterElementImpl('x', 34)..type = typeProvider.boolType,
_createFunctionParameter('', -1, type: typeProvider.stringType),
_createFunctionParameter('x', 34, type: typeProvider.boolType),
];
FunctionTypeImpl functionType = new FunctionTypeImpl(element);
element.type = functionType;
@ -82,7 +110,7 @@ f(String s, int i) {
f() {
int Function(String, bool x) foo;
}
''', [], [], <DartType>[functionType]);
''', [new LocalVariableElementImpl('foo', 37)], [], <DartType>[functionType]);
}
void test_listLiteral_const_noAnnotation() {
@ -201,6 +229,38 @@ get f => <String, int>{'a' : 1, 'b' : 2, 'c' : 3};
]);
}
void test_methodInvocation_getter() {
applyTypes(r'''
f(String s) {
return s.length;
}
''', [], [
_createFunctionParameter('s', 9),
new MethodElementImpl('length', -1)
], <DartType>[
typeProvider.stringType,
typeProvider.intType,
typeProvider.intType
]);
}
void test_methodInvocation_method() {
applyTypes(r'''
f(String s) {
return s.substring(3, 7);
}
''', [], [
_createFunctionParameter('s', 9),
new MethodElementImpl('length', -1)
], <DartType>[
typeProvider.stringType,
typeProvider.intType,
typeProvider.intType,
typeProvider.stringType,
typeProvider.stringType
]);
}
@failingTest
void test_typeAlias() {
TypeParameterElement B = _createTypeParameter('B', 42);
@ -213,7 +273,7 @@ get f => <String, int>{'a' : 1, 'b' : 2, 'c' : 3};
functionElement.typeParameters = <TypeParameterElement>[];
functionElement.returnType = B.type;
functionElement.parameters = [
new ParameterElementImpl('x', 48)..type = C.type,
_createFunctionParameter('x', 48, type: C.type),
];
FunctionTypeImpl functionType = new FunctionTypeImpl.forTypedef(element);
applyTypes(r'''
@ -221,7 +281,17 @@ f() {
A<int, String> foo;
}
//typedef B A<B, C>(C x);
''', [], [], <DartType>[functionType]);
''', [new LocalVariableElementImpl('foo', 23)], [], <DartType>[functionType]);
}
/// Return a newly created parameter element with the given [name] and
/// [offset].
ParameterElement _createFunctionParameter(String name, int offset,
{DartType type}) {
ParameterElementImpl parameter = new ParameterElementImpl(name, offset);
parameter.type = type;
parameter.parameterKind = ParameterKind.REQUIRED;
return parameter;
}
/// Return a newly created type parameter element with the given [name] and

View file

@ -26,6 +26,7 @@ fallthrough: Crash
fibonacci: Crash
for_in_scope: Crash
function_type_is_check: Crash
function_type_recovery: Crash
functions: Crash
illegal_named_function_expression: Crash
illegal_named_function_expression_scope: Crash
@ -68,7 +69,6 @@ inference/constructors_infer_from_arguments: Crash
inference/constructors_infer_from_arguments_const_with_upper_bound: Crash
inference/constructors_infer_from_arguments_downwards_from_constructor: Crash
inference/constructors_infer_from_arguments_factory: Crash
inference/constructors_infer_from_arguments_factory_calls_constructor: Crash
inference/constructors_infer_from_arguments_named: Crash
inference/constructors_infer_from_arguments_named_factory: Crash
inference/constructors_infer_from_arguments_redirecting: Crash
@ -180,7 +180,6 @@ inference/infer_conditional: Crash
inference/infer_consts_transitively_2: Crash
inference/infer_consts_transitively_2_a: Crash
inference/infer_correctly_on_multiple_variables_declared_together: Crash
inference/infer_field_override_with_substitution: Crash
inference/infer_from_complex_expressions_if_outer_most_value_is_precise: Crash
inference/infer_from_rhs_only_if_it_wont_conflict_with_overridden_fields2: Crash
inference/infer_from_rhs_only_if_it_wont_conflict_with_overridden_fields: Crash
@ -282,7 +281,6 @@ inference/refine_binary_expression_type_type_parameter_t_int: Crash
inference/refine_binary_expression_type_type_parameter_t_t: Crash
inference/static_method_tear_off: Crash
inference/string_literal: Crash
inference/subexpressions_of_explicitly_typed_fields: Crash
inference/super_index_set: Crash
inference/super_index_set_substitution: Crash
inference/super_initializer: Crash
@ -328,7 +326,6 @@ inference/unsafe_block_closure_inference_method_call_explicit_type_param: Crash
inference/unsafe_block_closure_inference_method_call_implicit_type_param: Crash
inference/void_return_type_subtypes_dynamic: Crash
inference_new/dependency_only_if_overloaded: Crash
inference_new/downwards_inference_inside_top_level: Crash
inference_new/field_inference_circularity: Crash
inference_new/indexed_assign_combiner: Crash
inference_new/infer_assign_to_implicit_this: Crash
@ -437,7 +434,6 @@ regress/issue_29942: Crash
regress/issue_29943: Crash
regress/issue_29978: Crash
regress/issue_29979: Crash
regress/issue_29981: Crash
regress/issue_29984: Crash
regress/issue_29985: Crash
regress/issue_31155: Crash # Issue 31155.
@ -446,7 +442,6 @@ regress/issue_31180: Crash
regress/issue_31184: Crash
regress/issue_31186: Crash
regress/issue_31187: Crash
regress/issue_31190: Crash
regress/issue_31198: Crash
reorder_super: Crash
runtime_checks/call_kinds: Crash