| // Copyright (c) 2016, 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 'dart:async'; |
| |
| import 'package:analyzer/dart/analysis/features.dart'; |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:analyzer/dart/ast/standard_ast_factory.dart'; |
| import 'package:analyzer/dart/ast/standard_resolution_map.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/dart/element/element.dart'; |
| import 'package:analyzer/src/dart/element/inheritance_manager2.dart'; |
| import 'package:analyzer/src/error/codes.dart'; |
| import 'package:analyzer/src/generated/element_resolver.dart'; |
| import 'package:analyzer/src/generated/engine.dart'; |
| import 'package:analyzer/src/generated/resolver.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| import 'package:analyzer/src/generated/testing/ast_test_factory.dart'; |
| import 'package:analyzer/src/generated/testing/element_factory.dart'; |
| import 'package:analyzer/src/source/source_resource.dart'; |
| import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import '../src/dart/resolution/driver_resolution.dart'; |
| import '../util/element_type_matchers.dart'; |
| import '../utils.dart'; |
| import 'analysis_context_factory.dart'; |
| import 'resolver_test_case.dart'; |
| import 'test_support.dart'; |
| |
| main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(AnnotationElementResolverTest); |
| defineReflectiveTests(ElementResolverTest); |
| defineReflectiveTests(PreviewDart2Test); |
| }); |
| } |
| |
| /// Wrapper around the test package's `fail` function. |
| /// |
| /// Unlike the test package's `fail` function, this function is not annotated |
| /// with @alwaysThrows, so we can call it at the top of a test method without |
| /// causing the rest of the method to be flagged as dead code. |
| void _fail(String message) { |
| fail(message); |
| } |
| |
| @reflectiveTest |
| class AnnotationElementResolverTest extends DriverResolutionTest { |
| test_class_namedConstructor() async { |
| newFile('/test/lib/a.dart', content: r''' |
| class A { |
| const A.named(); |
| } |
| '''); |
| await _validateAnnotation('', '@A.named()', (SimpleIdentifier name1, |
| SimpleIdentifier name2, |
| SimpleIdentifier name3, |
| Element annotationElement) { |
| expect(name1, isNotNull); |
| expect(name1.staticElement, isClassElement); |
| expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'A'); |
| expect(name2, isNotNull); |
| expect(name2.staticElement, isConstructorElement); |
| expect( |
| resolutionMap.staticElementForIdentifier(name2).displayName, 'named'); |
| expect(name3, isNull); |
| if (annotationElement is ConstructorElement) { |
| expect(annotationElement, same(name2.staticElement)); |
| expect(annotationElement.enclosingElement, name1.staticElement); |
| expect(annotationElement.displayName, 'named'); |
| expect(annotationElement.parameters, isEmpty); |
| } else { |
| fail('Expected "annotationElement" is ConstructorElement, ' |
| 'but (${annotationElement?.runtimeType}) $annotationElement found.'); |
| } |
| }); |
| } |
| |
| test_class_prefixed_namedConstructor() async { |
| newFile('/test/lib/a.dart', content: r''' |
| class A { |
| const A.named(); |
| } |
| '''); |
| await _validateAnnotation('as p', '@p.A.named()', (SimpleIdentifier name1, |
| SimpleIdentifier name2, |
| SimpleIdentifier name3, |
| Element annotationElement) { |
| expect(name1, isNotNull); |
| expect(name1.staticElement, isPrefixElement); |
| expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'p'); |
| expect(name2, isNotNull); |
| expect(name2.staticElement, isClassElement); |
| expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'A'); |
| expect(name3, isNotNull); |
| expect(name3.staticElement, isConstructorElement); |
| expect( |
| resolutionMap.staticElementForIdentifier(name3).displayName, 'named'); |
| if (annotationElement is ConstructorElement) { |
| expect(annotationElement, same(name3.staticElement)); |
| expect(annotationElement.enclosingElement, name2.staticElement); |
| expect(annotationElement.displayName, 'named'); |
| expect(annotationElement.parameters, isEmpty); |
| } else { |
| fail('Expected "annotationElement" is ConstructorElement, ' |
| 'but (${annotationElement?.runtimeType}) $annotationElement found.'); |
| } |
| }); |
| } |
| |
| test_class_prefixed_staticConstField() async { |
| newFile('/test/lib/a.dart', content: r''' |
| class A { |
| static const V = 0; |
| } |
| '''); |
| await _validateAnnotation('as p', '@p.A.V', (SimpleIdentifier name1, |
| SimpleIdentifier name2, |
| SimpleIdentifier name3, |
| Element annotationElement) { |
| expect(name1, isNotNull); |
| expect(name1.staticElement, isPrefixElement); |
| expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'p'); |
| expect(name2, isNotNull); |
| expect(name2.staticElement, isClassElement); |
| expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'A'); |
| expect(name3, isNotNull); |
| expect(name3.staticElement, isPropertyAccessorElement); |
| expect(resolutionMap.staticElementForIdentifier(name3).displayName, 'V'); |
| if (annotationElement is PropertyAccessorElement) { |
| expect(annotationElement, same(name3.staticElement)); |
| expect(annotationElement.enclosingElement, name2.staticElement); |
| expect(annotationElement.displayName, 'V'); |
| } else { |
| fail('Expected "annotationElement" is PropertyAccessorElement, ' |
| 'but (${annotationElement?.runtimeType}) $annotationElement found.'); |
| } |
| }); |
| } |
| |
| test_class_prefixed_unnamedConstructor() async { |
| newFile('/test/lib/a.dart', content: r''' |
| class A { |
| const A(); |
| } |
| '''); |
| await _validateAnnotation('as p', '@p.A', (SimpleIdentifier name1, |
| SimpleIdentifier name2, |
| SimpleIdentifier name3, |
| Element annotationElement) { |
| expect(name1, isNotNull); |
| expect(name1.staticElement, isPrefixElement); |
| expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'p'); |
| expect(name2, isNotNull); |
| expect(name2.staticElement, isClassElement); |
| expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'A'); |
| expect(name3, isNull); |
| if (annotationElement is ConstructorElement) { |
| expect(annotationElement.enclosingElement, name2.staticElement); |
| expect(annotationElement.displayName, ''); |
| expect(annotationElement.parameters, isEmpty); |
| } else { |
| fail('Expected "annotationElement" is ConstructorElement, ' |
| 'but (${annotationElement?.runtimeType}) $annotationElement found.'); |
| } |
| }); |
| } |
| |
| test_class_staticConstField() async { |
| newFile('/test/lib/a.dart', content: r''' |
| class A { |
| static const V = 0; |
| } |
| '''); |
| await _validateAnnotation('', '@A.V', (SimpleIdentifier name1, |
| SimpleIdentifier name2, |
| SimpleIdentifier name3, |
| Element annotationElement) { |
| expect(name1, isNotNull); |
| expect(name1.staticElement, isClassElement); |
| expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'A'); |
| expect(name2, isNotNull); |
| expect(name2.staticElement, isPropertyAccessorElement); |
| expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'V'); |
| expect(name3, isNull); |
| if (annotationElement is PropertyAccessorElement) { |
| expect(annotationElement, same(name2.staticElement)); |
| expect(annotationElement.enclosingElement, name1.staticElement); |
| expect(annotationElement.displayName, 'V'); |
| } else { |
| fail('Expected "annotationElement" is PropertyAccessorElement, ' |
| 'but (${annotationElement?.runtimeType}) $annotationElement found.'); |
| } |
| }); |
| } |
| |
| test_class_unnamedConstructor() async { |
| newFile('/test/lib/a.dart', content: r''' |
| class A { |
| const A(); |
| } |
| '''); |
| await _validateAnnotation('', '@A', (SimpleIdentifier name1, |
| SimpleIdentifier name2, |
| SimpleIdentifier name3, |
| Element annotationElement) { |
| expect(name1, isNotNull); |
| expect(name1.staticElement, isClassElement); |
| expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'A'); |
| expect(name2, isNull); |
| expect(name3, isNull); |
| if (annotationElement is ConstructorElement) { |
| expect(annotationElement.enclosingElement, name1.staticElement); |
| expect(annotationElement.displayName, ''); |
| expect(annotationElement.parameters, isEmpty); |
| } else { |
| fail('Expected "annotationElement" is ConstructorElement, ' |
| 'but (${annotationElement?.runtimeType}) $annotationElement found.'); |
| } |
| }); |
| } |
| |
| test_topLevelVariable() async { |
| newFile('/test/lib/a.dart', content: r''' |
| const V = 0; |
| '''); |
| await _validateAnnotation('', '@V', (SimpleIdentifier name1, |
| SimpleIdentifier name2, |
| SimpleIdentifier name3, |
| Element annotationElement) { |
| expect(name1, isNotNull); |
| expect(name1.staticElement, isPropertyAccessorElement); |
| expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'V'); |
| expect(name2, isNull); |
| expect(name3, isNull); |
| if (annotationElement is PropertyAccessorElement) { |
| expect(annotationElement, same(name1.staticElement)); |
| expect(annotationElement.enclosingElement, isCompilationUnitElement); |
| expect(annotationElement.displayName, 'V'); |
| } else { |
| fail('Expected "annotationElement" is PropertyAccessorElement, ' |
| 'but (${annotationElement?.runtimeType}) $annotationElement found.'); |
| } |
| }); |
| } |
| |
| test_topLevelVariable_prefixed() async { |
| newFile('/test/lib/a.dart', content: r''' |
| const V = 0; |
| '''); |
| await _validateAnnotation('as p', '@p.V', (SimpleIdentifier name1, |
| SimpleIdentifier name2, |
| SimpleIdentifier name3, |
| Element annotationElement) { |
| expect(name1, isNotNull); |
| expect(name1.staticElement, isPrefixElement); |
| expect(resolutionMap.staticElementForIdentifier(name1).displayName, 'p'); |
| expect(name2, isNotNull); |
| expect(name2.staticElement, isPropertyAccessorElement); |
| expect(resolutionMap.staticElementForIdentifier(name2).displayName, 'V'); |
| expect(name3, isNull); |
| if (annotationElement is PropertyAccessorElement) { |
| expect(annotationElement, same(name2.staticElement)); |
| expect(annotationElement.enclosingElement, isCompilationUnitElement); |
| expect(annotationElement.displayName, 'V'); |
| } else { |
| fail('Expected "annotationElement" is PropertyAccessorElement, ' |
| 'but (${annotationElement?.runtimeType}) $annotationElement found.'); |
| } |
| }); |
| } |
| |
| Future<void> _validateAnnotation( |
| String annotationPrefix, |
| String annotationText, |
| validator(SimpleIdentifier name1, SimpleIdentifier name2, |
| SimpleIdentifier name3, Element annotationElement)) async { |
| addTestFile(''' |
| import 'a.dart' $annotationPrefix; |
| $annotationText |
| class C {} |
| '''); |
| await resolveTestFile(); |
| |
| var clazz = findNode.classDeclaration('C'); |
| Annotation annotation = clazz.metadata.single; |
| Identifier name = annotation.name; |
| Element annotationElement = annotation.element; |
| if (name is SimpleIdentifier) { |
| validator(name, null, annotation.constructorName, annotationElement); |
| } else if (name is PrefixedIdentifier) { |
| validator(name.prefix, name.identifier, annotation.constructorName, |
| annotationElement); |
| } else { |
| fail('Uknown "name": ${name?.runtimeType} $name'); |
| } |
| } |
| } |
| |
| @reflectiveTest |
| class ElementResolverTest extends EngineTestCase with ResourceProviderMixin { |
| /** |
| * The error listener to which errors will be reported. |
| */ |
| GatheringErrorListener _listener; |
| |
| /** |
| * The type provider used to access the types. |
| */ |
| TypeProvider _typeProvider; |
| |
| /** |
| * The library containing the code being resolved. |
| */ |
| LibraryElementImpl _definingLibrary; |
| |
| /** |
| * The resolver visitor that maintains the state for the resolver. |
| */ |
| ResolverVisitor _visitor; |
| |
| /** |
| * The resolver being used to resolve the test cases. |
| */ |
| ElementResolver _resolver; |
| |
| void fail_visitExportDirective_combinators() { |
| _fail("Not yet tested"); |
| // Need to set up the exported library so that the identifier can be |
| // resolved. |
| ExportDirective directive = AstTestFactory.exportDirective2(null, [ |
| AstTestFactory.hideCombinator2(["A"]) |
| ]); |
| _resolveNode(directive); |
| _listener.assertNoErrors(); |
| } |
| |
| void fail_visitFunctionExpressionInvocation() { |
| _fail("Not yet tested"); |
| _listener.assertNoErrors(); |
| } |
| |
| void fail_visitImportDirective_combinators_noPrefix() { |
| _fail("Not yet tested"); |
| // Need to set up the imported library so that the identifier can be |
| // resolved. |
| ImportDirective directive = AstTestFactory.importDirective3(null, null, [ |
| AstTestFactory.showCombinator2(["A"]) |
| ]); |
| _resolveNode(directive); |
| _listener.assertNoErrors(); |
| } |
| |
| void fail_visitImportDirective_combinators_prefix() { |
| _fail("Not yet tested"); |
| // Need to set up the imported library so that the identifiers can be |
| // resolved. |
| String prefixName = "p"; |
| _definingLibrary.imports = <ImportElement>[ |
| ElementFactory.importFor(null, ElementFactory.prefix(prefixName)) |
| ]; |
| ImportDirective directive = |
| AstTestFactory.importDirective3(null, prefixName, [ |
| AstTestFactory.showCombinator2(["A"]), |
| AstTestFactory.hideCombinator2(["B"]) |
| ]); |
| _resolveNode(directive); |
| _listener.assertNoErrors(); |
| } |
| |
| void fail_visitRedirectingConstructorInvocation() { |
| _fail("Not yet tested"); |
| _listener.assertNoErrors(); |
| } |
| |
| @override |
| void setUp() { |
| super.setUp(); |
| _listener = new GatheringErrorListener(); |
| _createResolver(); |
| } |
| |
| test_lookUpMethodInInterfaces() async { |
| InterfaceType intType = _typeProvider.intType; |
| // |
| // abstract class A { int operator[](int index); } |
| // |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| MethodElement operator = |
| ElementFactory.methodElement("[]", intType, [intType]); |
| classA.methods = <MethodElement>[operator]; |
| // |
| // class B implements A {} |
| // |
| ClassElementImpl classB = ElementFactory.classElement2("B"); |
| classB.interfaces = <InterfaceType>[classA.type]; |
| // |
| // class C extends Object with B {} |
| // |
| ClassElementImpl classC = ElementFactory.classElement2("C"); |
| classC.mixins = <InterfaceType>[classB.type]; |
| // |
| // class D extends C {} |
| // |
| ClassElementImpl classD = ElementFactory.classElement("D", classC.type); |
| // |
| // D a; |
| // a[i]; |
| // |
| SimpleIdentifier array = AstTestFactory.identifier3("a"); |
| array.staticType = classD.type; |
| IndexExpression expression = |
| AstTestFactory.indexExpression(array, AstTestFactory.identifier3("i")); |
| expect(_resolveIndexExpression(expression), same(operator)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitAssignmentExpression_compound() async { |
| InterfaceType intType = _typeProvider.intType; |
| SimpleIdentifier leftHandSide = AstTestFactory.identifier3("a"); |
| leftHandSide.staticType = intType; |
| AssignmentExpression assignment = AstTestFactory.assignmentExpression( |
| leftHandSide, TokenType.PLUS_EQ, AstTestFactory.integer(1)); |
| _resolveNode(assignment); |
| expect( |
| assignment.staticElement, same(getMethod(_typeProvider.numType, "+"))); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitAssignmentExpression_simple() async { |
| AssignmentExpression expression = AstTestFactory.assignmentExpression( |
| AstTestFactory.identifier3("x"), |
| TokenType.EQ, |
| AstTestFactory.integer(0)); |
| _resolveNode(expression); |
| expect(expression.staticElement, isNull); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitBinaryExpression_bangEq() async { |
| // String i; |
| // var j; |
| // i == j |
| InterfaceType stringType = _typeProvider.stringType; |
| SimpleIdentifier left = AstTestFactory.identifier3("i"); |
| left.staticType = stringType; |
| BinaryExpression expression = AstTestFactory.binaryExpression( |
| left, TokenType.BANG_EQ, AstTestFactory.identifier3("j")); |
| _resolveNode(expression); |
| var stringElement = stringType.element; |
| expect(expression.staticElement, isNotNull); |
| expect( |
| expression.staticElement, |
| stringElement.lookUpMethod( |
| TokenType.EQ_EQ.lexeme, stringElement.library)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitBinaryExpression_eq() async { |
| // String i; |
| // var j; |
| // i == j |
| InterfaceType stringType = _typeProvider.stringType; |
| SimpleIdentifier left = AstTestFactory.identifier3("i"); |
| left.staticType = stringType; |
| BinaryExpression expression = AstTestFactory.binaryExpression( |
| left, TokenType.EQ_EQ, AstTestFactory.identifier3("j")); |
| _resolveNode(expression); |
| var stringElement = stringType.element; |
| expect( |
| expression.staticElement, |
| stringElement.lookUpMethod( |
| TokenType.EQ_EQ.lexeme, stringElement.library)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitBinaryExpression_plus() async { |
| // num i; |
| // var j; |
| // i + j |
| InterfaceType numType = _typeProvider.numType; |
| SimpleIdentifier left = AstTestFactory.identifier3("i"); |
| left.staticType = numType; |
| BinaryExpression expression = AstTestFactory.binaryExpression( |
| left, TokenType.PLUS, AstTestFactory.identifier3("j")); |
| _resolveNode(expression); |
| expect(expression.staticElement, getMethod(numType, "+")); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitBreakStatement_withLabel() async { |
| // loop: while (true) { |
| // break loop; |
| // } |
| String label = "loop"; |
| LabelElementImpl labelElement = new LabelElementImpl.forNode( |
| AstTestFactory.identifier3(label), false, false); |
| BreakStatement breakStatement = AstTestFactory.breakStatement2(label); |
| Expression condition = AstTestFactory.booleanLiteral(true); |
| WhileStatement whileStatement = |
| AstTestFactory.whileStatement(condition, breakStatement); |
| expect(_resolveBreak(breakStatement, labelElement, whileStatement), |
| same(labelElement)); |
| expect(breakStatement.target, same(whileStatement)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitBreakStatement_withoutLabel() async { |
| BreakStatement statement = AstTestFactory.breakStatement(); |
| _resolveStatement(statement, null, null); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitCommentReference_prefixedIdentifier_class_getter() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| // set accessors |
| String propName = "p"; |
| PropertyAccessorElement getter = |
| ElementFactory.getterElement(propName, false, _typeProvider.intType); |
| PropertyAccessorElement setter = |
| ElementFactory.setterElement(propName, false, _typeProvider.intType); |
| classA.accessors = <PropertyAccessorElement>[getter, setter]; |
| // set name scope |
| _visitor.nameScope = new EnclosedScope(null) |
| ..defineNameWithoutChecking('A', classA); |
| // prepare "A.p" |
| PrefixedIdentifier prefixed = AstTestFactory.identifier5('A', 'p'); |
| CommentReference commentReference = |
| astFactory.commentReference(null, prefixed); |
| // resolve |
| _resolveNode(commentReference); |
| expect(prefixed.prefix.staticElement, classA); |
| expect(prefixed.identifier.staticElement, getter); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitCommentReference_prefixedIdentifier_class_method() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| // set method |
| MethodElement method = |
| ElementFactory.methodElement("m", _typeProvider.intType); |
| classA.methods = <MethodElement>[method]; |
| // set name scope |
| _visitor.nameScope = new EnclosedScope(null) |
| ..defineNameWithoutChecking('A', classA); |
| // prepare "A.m" |
| PrefixedIdentifier prefixed = AstTestFactory.identifier5('A', 'm'); |
| CommentReference commentReference = |
| astFactory.commentReference(null, prefixed); |
| // resolve |
| _resolveNode(commentReference); |
| expect(prefixed.prefix.staticElement, classA); |
| expect(prefixed.identifier.staticElement, method); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitCommentReference_prefixedIdentifier_class_operator() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| // set method |
| MethodElement method = |
| ElementFactory.methodElement("==", _typeProvider.boolType); |
| classA.methods = <MethodElement>[method]; |
| // set name scope |
| _visitor.nameScope = new EnclosedScope(null) |
| ..defineNameWithoutChecking('A', classA); |
| // prepare "A.==" |
| PrefixedIdentifier prefixed = AstTestFactory.identifier5('A', '=='); |
| CommentReference commentReference = |
| astFactory.commentReference(null, prefixed); |
| // resolve |
| _resolveNode(commentReference); |
| expect(prefixed.prefix.staticElement, classA); |
| expect(prefixed.identifier.staticElement, method); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitConstructorName_named() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| String constructorName = "a"; |
| ConstructorElement constructor = |
| ElementFactory.constructorElement2(classA, constructorName); |
| classA.constructors = <ConstructorElement>[constructor]; |
| ConstructorName name = AstTestFactory.constructorName( |
| AstTestFactory.typeName(classA), constructorName); |
| _resolveNode(name); |
| expect(name.staticElement, same(constructor)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitConstructorName_unnamed() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| String constructorName = null; |
| ConstructorElement constructor = |
| ElementFactory.constructorElement2(classA, constructorName); |
| classA.constructors = <ConstructorElement>[constructor]; |
| ConstructorName name = AstTestFactory.constructorName( |
| AstTestFactory.typeName(classA), constructorName); |
| _resolveNode(name); |
| expect(name.staticElement, same(constructor)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitContinueStatement_withLabel() async { |
| // loop: while (true) { |
| // continue loop; |
| // } |
| String label = "loop"; |
| LabelElementImpl labelElement = new LabelElementImpl.forNode( |
| AstTestFactory.identifier3(label), false, false); |
| ContinueStatement continueStatement = |
| AstTestFactory.continueStatement(label); |
| Expression condition = AstTestFactory.booleanLiteral(true); |
| WhileStatement whileStatement = |
| AstTestFactory.whileStatement(condition, continueStatement); |
| expect(_resolveContinue(continueStatement, labelElement, whileStatement), |
| same(labelElement)); |
| expect(continueStatement.target, same(whileStatement)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitContinueStatement_withoutLabel() async { |
| ContinueStatement statement = AstTestFactory.continueStatement(); |
| _resolveStatement(statement, null, null); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitEnumDeclaration() async { |
| CompilationUnitElementImpl compilationUnitElement = |
| ElementFactory.compilationUnit('foo.dart'); |
| EnumElementImpl enumElement = |
| ElementFactory.enumElement(_typeProvider, ('E')); |
| compilationUnitElement.enums = <ClassElement>[enumElement]; |
| EnumDeclaration enumNode = AstTestFactory.enumDeclaration2('E', []); |
| Annotation annotationNode = |
| AstTestFactory.annotation(AstTestFactory.identifier3('a')); |
| annotationNode.element = ElementFactory.classElement2('A'); |
| annotationNode.elementAnnotation = |
| new ElementAnnotationImpl(compilationUnitElement); |
| enumNode.metadata.add(annotationNode); |
| enumNode.name.staticElement = enumElement; |
| List<ElementAnnotation> metadata = <ElementAnnotation>[ |
| annotationNode.elementAnnotation |
| ]; |
| _resolveNode(enumNode); |
| expect(metadata[0].element, annotationNode.element); |
| } |
| |
| test_visitExportDirective_noCombinators() async { |
| ExportDirective directive = AstTestFactory.exportDirective2(null); |
| directive.element = ElementFactory.exportFor( |
| ElementFactory.library(_definingLibrary.context, "lib")); |
| _resolveNode(directive); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitFieldFormalParameter() async { |
| String fieldName = "f"; |
| InterfaceType intType = _typeProvider.intType; |
| FieldElementImpl fieldElement = |
| ElementFactory.fieldElement(fieldName, false, false, false, intType); |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| classA.fields = <FieldElement>[fieldElement]; |
| FieldFormalParameter parameter = |
| AstTestFactory.fieldFormalParameter2(fieldName); |
| FieldFormalParameterElementImpl parameterElement = |
| ElementFactory.fieldFormalParameter(parameter.identifier); |
| parameterElement.field = fieldElement; |
| parameterElement.type = intType; |
| parameter.identifier.staticElement = parameterElement; |
| _resolveInClass(parameter, classA); |
| expect(resolutionMap.elementDeclaredByFormalParameter(parameter).type, |
| same(intType)); |
| } |
| |
| test_visitImportDirective_noCombinators_noPrefix() async { |
| ImportDirective directive = AstTestFactory.importDirective3(null, null); |
| directive.element = ElementFactory.importFor( |
| ElementFactory.library(_definingLibrary.context, "lib"), null); |
| _resolveNode(directive); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitImportDirective_noCombinators_prefix() async { |
| String prefixName = "p"; |
| ImportElement importElement = ElementFactory.importFor( |
| ElementFactory.library(_definingLibrary.context, "lib"), |
| ElementFactory.prefix(prefixName)); |
| _definingLibrary.imports = <ImportElement>[importElement]; |
| ImportDirective directive = |
| AstTestFactory.importDirective3(null, prefixName); |
| directive.element = importElement; |
| _resolveNode(directive); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitImportDirective_withCombinators() async { |
| ShowCombinator combinator = AstTestFactory.showCombinator2(["A", "B", "C"]); |
| ImportDirective directive = |
| AstTestFactory.importDirective3(null, null, [combinator]); |
| LibraryElementImpl library = |
| ElementFactory.library(_definingLibrary.context, "lib"); |
| TopLevelVariableElementImpl varA = |
| ElementFactory.topLevelVariableElement2("A"); |
| TopLevelVariableElementImpl varB = |
| ElementFactory.topLevelVariableElement2("B"); |
| TopLevelVariableElementImpl varC = |
| ElementFactory.topLevelVariableElement2("C"); |
| CompilationUnitElementImpl unit = |
| library.definingCompilationUnit as CompilationUnitElementImpl; |
| unit.accessors = <PropertyAccessorElement>[ |
| varA.getter, |
| varA.setter, |
| varB.getter, |
| varC.setter |
| ]; |
| unit.topLevelVariables = <TopLevelVariableElement>[varA, varB, varC]; |
| directive.element = ElementFactory.importFor(library, null); |
| _resolveNode(directive); |
| expect(combinator.shownNames[0].staticElement, same(varA)); |
| expect(combinator.shownNames[1].staticElement, same(varB)); |
| expect(combinator.shownNames[2].staticElement, same(varC)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitIndexExpression_get() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| InterfaceType intType = _typeProvider.intType; |
| MethodElement getter = |
| ElementFactory.methodElement("[]", intType, [intType]); |
| classA.methods = <MethodElement>[getter]; |
| SimpleIdentifier array = AstTestFactory.identifier3("a"); |
| array.staticType = classA.type; |
| IndexExpression expression = |
| AstTestFactory.indexExpression(array, AstTestFactory.identifier3("i")); |
| expect(_resolveIndexExpression(expression), same(getter)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitIndexExpression_set() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| InterfaceType intType = _typeProvider.intType; |
| MethodElement setter = |
| ElementFactory.methodElement("[]=", intType, [intType]); |
| classA.methods = <MethodElement>[setter]; |
| SimpleIdentifier array = AstTestFactory.identifier3("a"); |
| array.staticType = classA.type; |
| IndexExpression expression = |
| AstTestFactory.indexExpression(array, AstTestFactory.identifier3("i")); |
| AstTestFactory.assignmentExpression( |
| expression, TokenType.EQ, AstTestFactory.integer(0)); |
| expect(_resolveIndexExpression(expression), same(setter)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitInstanceCreationExpression_named() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| String constructorName = "a"; |
| ConstructorElement constructor = |
| ElementFactory.constructorElement2(classA, constructorName); |
| classA.constructors = <ConstructorElement>[constructor]; |
| ConstructorName name = AstTestFactory.constructorName( |
| AstTestFactory.typeName(classA), constructorName); |
| name.staticElement = constructor; |
| InstanceCreationExpression creation = |
| AstTestFactory.instanceCreationExpression(Keyword.NEW, name); |
| _resolveNode(creation); |
| expect(creation.staticElement, same(constructor)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitInstanceCreationExpression_unnamed() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| String constructorName = null; |
| ConstructorElement constructor = |
| ElementFactory.constructorElement2(classA, constructorName); |
| classA.constructors = <ConstructorElement>[constructor]; |
| ConstructorName name = AstTestFactory.constructorName( |
| AstTestFactory.typeName(classA), constructorName); |
| name.staticElement = constructor; |
| InstanceCreationExpression creation = |
| AstTestFactory.instanceCreationExpression(Keyword.NEW, name); |
| _resolveNode(creation); |
| expect(creation.staticElement, same(constructor)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitInstanceCreationExpression_unnamed_namedParameter() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| String constructorName = null; |
| ConstructorElementImpl constructor = |
| ElementFactory.constructorElement2(classA, constructorName); |
| String parameterName = "a"; |
| ParameterElement parameter = ElementFactory.namedParameter(parameterName); |
| constructor.parameters = <ParameterElement>[parameter]; |
| classA.constructors = <ConstructorElement>[constructor]; |
| ConstructorName name = AstTestFactory.constructorName( |
| AstTestFactory.typeName(classA), constructorName); |
| name.staticElement = constructor; |
| InstanceCreationExpression creation = |
| AstTestFactory.instanceCreationExpression(Keyword.NEW, name, [ |
| AstTestFactory.namedExpression2(parameterName, AstTestFactory.integer(0)) |
| ]); |
| _resolveNode(creation); |
| expect(creation.staticElement, same(constructor)); |
| expect( |
| (creation.argumentList.arguments[0] as NamedExpression) |
| .name |
| .label |
| .staticElement, |
| same(parameter)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitMethodInvocation() async { |
| InterfaceType numType = _typeProvider.numType; |
| SimpleIdentifier left = AstTestFactory.identifier3("i"); |
| left.staticType = numType; |
| String methodName = "abs"; |
| MethodInvocation invocation = |
| AstTestFactory.methodInvocation(left, methodName); |
| _resolveNode(invocation); |
| expect(invocation.methodName.staticElement, |
| same(getMethod(numType, methodName))); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitPostfixExpression() async { |
| InterfaceType numType = _typeProvider.numType; |
| SimpleIdentifier operand = AstTestFactory.identifier3("i"); |
| operand.staticType = numType; |
| PostfixExpression expression = |
| AstTestFactory.postfixExpression(operand, TokenType.PLUS_PLUS); |
| _resolveNode(expression); |
| expect(expression.staticElement, getMethod(numType, "+")); |
| _listener.assertNoErrors(); |
| } |
| |
| @failingTest |
| test_visitPostfixExpression_bang() async { |
| InterfaceType numType = _typeProvider.numType; |
| SimpleIdentifier operand = AstTestFactory.identifier3("i"); |
| operand.staticType = numType; |
| PostfixExpression expression = |
| AstTestFactory.postfixExpression(operand, TokenType.BANG); |
| // TODO(danrubel): fails with Unsupported operation |
| _resolveNode(expression); |
| _listener.assertErrorsWithCodes([StaticTypeWarningCode.UNDEFINED_OPERATOR]); |
| } |
| |
| @failingTest |
| test_visitPostfixExpression_bang_NNBD() async { |
| // TODO(danrubel): enable NNBD |
| InterfaceType numType = _typeProvider.numType; |
| SimpleIdentifier operand = AstTestFactory.identifier3("i"); |
| operand.staticType = numType; |
| PostfixExpression expression = |
| AstTestFactory.postfixExpression(operand, TokenType.BANG); |
| _resolveNode(expression); |
| // TODO(danrubel): fails with Unsupported operation |
| expect(expression.staticElement, getMethod(numType, "!")); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitPrefixedIdentifier_dynamic() async { |
| DartType dynamicType = _typeProvider.dynamicType; |
| SimpleIdentifier target = AstTestFactory.identifier3("a"); |
| VariableElementImpl variable = ElementFactory.localVariableElement(target); |
| variable.type = dynamicType; |
| target.staticElement = variable; |
| target.staticType = dynamicType; |
| PrefixedIdentifier identifier = |
| AstTestFactory.identifier(target, AstTestFactory.identifier3("b")); |
| _resolveNode(identifier); |
| expect(identifier.staticElement, isNull); |
| expect(identifier.identifier.staticElement, isNull); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitPrefixedIdentifier_nonDynamic() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| String getterName = "b"; |
| PropertyAccessorElement getter = |
| ElementFactory.getterElement(getterName, false, _typeProvider.intType); |
| classA.accessors = <PropertyAccessorElement>[getter]; |
| SimpleIdentifier target = AstTestFactory.identifier3("a"); |
| VariableElementImpl variable = ElementFactory.localVariableElement(target); |
| variable.type = classA.type; |
| target.staticElement = variable; |
| target.staticType = classA.type; |
| PrefixedIdentifier identifier = AstTestFactory.identifier( |
| target, AstTestFactory.identifier3(getterName)); |
| _resolveNode(identifier); |
| expect(identifier.staticElement, same(getter)); |
| expect(identifier.identifier.staticElement, same(getter)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitPrefixedIdentifier_staticClassMember_getter() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| // set accessors |
| String propName = "b"; |
| PropertyAccessorElement getter = |
| ElementFactory.getterElement(propName, false, _typeProvider.intType); |
| PropertyAccessorElement setter = |
| ElementFactory.setterElement(propName, false, _typeProvider.intType); |
| classA.accessors = <PropertyAccessorElement>[getter, setter]; |
| // prepare "A.m" |
| SimpleIdentifier target = AstTestFactory.identifier3("A"); |
| target.staticElement = classA; |
| target.staticType = classA.type; |
| PrefixedIdentifier identifier = |
| AstTestFactory.identifier(target, AstTestFactory.identifier3(propName)); |
| // resolve |
| _resolveNode(identifier); |
| expect(identifier.staticElement, same(getter)); |
| expect(identifier.identifier.staticElement, same(getter)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitPrefixedIdentifier_staticClassMember_method() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| // set methods |
| String propName = "m"; |
| MethodElement method = |
| ElementFactory.methodElement("m", _typeProvider.intType); |
| classA.methods = <MethodElement>[method]; |
| // prepare "A.m" |
| SimpleIdentifier target = AstTestFactory.identifier3("A"); |
| target.staticElement = classA; |
| target.staticType = classA.type; |
| PrefixedIdentifier identifier = |
| AstTestFactory.identifier(target, AstTestFactory.identifier3(propName)); |
| AstTestFactory.assignmentExpression( |
| identifier, TokenType.EQ, AstTestFactory.nullLiteral()); |
| // resolve |
| _resolveNode(identifier); |
| expect(identifier.staticElement, same(method)); |
| expect(identifier.identifier.staticElement, same(method)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitPrefixedIdentifier_staticClassMember_setter() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| // set accessors |
| String propName = "b"; |
| PropertyAccessorElement getter = |
| ElementFactory.getterElement(propName, false, _typeProvider.intType); |
| PropertyAccessorElement setter = |
| ElementFactory.setterElement(propName, false, _typeProvider.intType); |
| classA.accessors = <PropertyAccessorElement>[getter, setter]; |
| // prepare "A.b = null" |
| SimpleIdentifier target = AstTestFactory.identifier3("A"); |
| target.staticElement = classA; |
| target.staticType = classA.type; |
| PrefixedIdentifier identifier = |
| AstTestFactory.identifier(target, AstTestFactory.identifier3(propName)); |
| AstTestFactory.assignmentExpression( |
| identifier, TokenType.EQ, AstTestFactory.nullLiteral()); |
| // resolve |
| _resolveNode(identifier); |
| expect(identifier.staticElement, same(setter)); |
| expect(identifier.identifier.staticElement, same(setter)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitPrefixExpression() async { |
| InterfaceType numType = _typeProvider.numType; |
| SimpleIdentifier operand = AstTestFactory.identifier3("i"); |
| operand.staticType = numType; |
| PrefixExpression expression = |
| AstTestFactory.prefixExpression(TokenType.PLUS_PLUS, operand); |
| _resolveNode(expression); |
| expect(expression.staticElement, getMethod(numType, "+")); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitPropertyAccess_getter_identifier() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| String getterName = "b"; |
| PropertyAccessorElement getter = |
| ElementFactory.getterElement(getterName, false, _typeProvider.intType); |
| classA.accessors = <PropertyAccessorElement>[getter]; |
| SimpleIdentifier target = AstTestFactory.identifier3("a"); |
| target.staticType = classA.type; |
| PropertyAccess access = AstTestFactory.propertyAccess2(target, getterName); |
| _resolveNode(access); |
| expect(access.propertyName.staticElement, same(getter)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitPropertyAccess_getter_super() async { |
| // |
| // class A { |
| // int get b; |
| // } |
| // class B { |
| // ... super.m ... |
| // } |
| // |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| String getterName = "b"; |
| PropertyAccessorElement getter = |
| ElementFactory.getterElement(getterName, false, _typeProvider.intType); |
| classA.accessors = <PropertyAccessorElement>[getter]; |
| SuperExpression target = AstTestFactory.superExpression(); |
| target.staticType = ElementFactory.classElement("B", classA.type).type; |
| PropertyAccess access = AstTestFactory.propertyAccess2(target, getterName); |
| AstTestFactory.methodDeclaration2( |
| null, |
| null, |
| null, |
| null, |
| AstTestFactory.identifier3("m"), |
| AstTestFactory.formalParameterList(), |
| AstTestFactory.expressionFunctionBody(access)); |
| _resolveNode(access); |
| expect(access.propertyName.staticElement, same(getter)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitPropertyAccess_setter_this() async { |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| String setterName = "b"; |
| PropertyAccessorElement setter = |
| ElementFactory.setterElement(setterName, false, _typeProvider.intType); |
| classA.accessors = <PropertyAccessorElement>[setter]; |
| ThisExpression target = AstTestFactory.thisExpression(); |
| target.staticType = classA.type; |
| PropertyAccess access = AstTestFactory.propertyAccess2(target, setterName); |
| AstTestFactory.assignmentExpression( |
| access, TokenType.EQ, AstTestFactory.integer(0)); |
| _resolveNode(access); |
| expect(access.propertyName.staticElement, same(setter)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitSimpleIdentifier_classScope() async { |
| InterfaceType doubleType = _typeProvider.doubleType; |
| String fieldName = "NAN"; |
| SimpleIdentifier node = AstTestFactory.identifier3(fieldName); |
| _resolveInClass(node, doubleType.element); |
| expect(node.staticElement, getGetter(doubleType, fieldName)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitSimpleIdentifier_dynamic() async { |
| SimpleIdentifier node = AstTestFactory.identifier3("dynamic"); |
| _resolveIdentifier(node); |
| expect(node.staticElement, same(_typeProvider.dynamicType.element)); |
| expect(node.staticType, same(_typeProvider.typeType)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitSimpleIdentifier_lexicalScope() async { |
| SimpleIdentifier node = AstTestFactory.identifier3("i"); |
| VariableElementImpl element = ElementFactory.localVariableElement(node); |
| expect(_resolveIdentifier(node, [element]), same(element)); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitSimpleIdentifier_lexicalScope_field_setter() async { |
| InterfaceType intType = _typeProvider.intType; |
| ClassElementImpl classA = ElementFactory.classElement2("A"); |
| String fieldName = "a"; |
| FieldElement field = |
| ElementFactory.fieldElement(fieldName, false, false, false, intType); |
| classA.fields = <FieldElement>[field]; |
| classA.accessors = <PropertyAccessorElement>[field.getter, field.setter]; |
| SimpleIdentifier node = AstTestFactory.identifier3(fieldName); |
| AstTestFactory.assignmentExpression( |
| node, TokenType.EQ, AstTestFactory.integer(0)); |
| _resolveInClass(node, classA); |
| PropertyAccessorElement element = node.staticElement; |
| expect(element.isSetter, isTrue); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitSuperConstructorInvocation() async { |
| ClassElementImpl superclass = ElementFactory.classElement2("A"); |
| ConstructorElementImpl superConstructor = |
| ElementFactory.constructorElement2(superclass, null); |
| superclass.constructors = <ConstructorElement>[superConstructor]; |
| ClassElementImpl subclass = |
| ElementFactory.classElement("B", superclass.type); |
| ConstructorElementImpl subConstructor = |
| ElementFactory.constructorElement2(subclass, null); |
| subclass.constructors = <ConstructorElement>[subConstructor]; |
| SuperConstructorInvocation invocation = |
| AstTestFactory.superConstructorInvocation(); |
| AstTestFactory.classDeclaration(null, 'C', null, null, null, null, [ |
| AstTestFactory.constructorDeclaration(null, 'C', null, [invocation]) |
| ]); |
| _resolveInClass(invocation, subclass); |
| expect(invocation.staticElement, superConstructor); |
| _listener.assertNoErrors(); |
| } |
| |
| test_visitSuperConstructorInvocation_namedParameter() async { |
| ClassElementImpl superclass = ElementFactory.classElement2("A"); |
| ConstructorElementImpl superConstructor = |
| ElementFactory.constructorElement2(superclass, null); |
| String parameterName = "p"; |
| ParameterElement parameter = ElementFactory.namedParameter(parameterName); |
| superConstructor.parameters = <ParameterElement>[parameter]; |
| superclass.constructors = <ConstructorElement>[superConstructor]; |
| ClassElementImpl subclass = |
| ElementFactory.classElement("B", superclass.type); |
| ConstructorElementImpl subConstructor = |
| ElementFactory.constructorElement2(subclass, null); |
| subclass.constructors = <ConstructorElement>[subConstructor]; |
| SuperConstructorInvocation invocation = |
| AstTestFactory.superConstructorInvocation([ |
| AstTestFactory.namedExpression2(parameterName, AstTestFactory.integer(0)) |
| ]); |
| AstTestFactory.classDeclaration(null, 'C', null, null, null, null, [ |
| AstTestFactory.constructorDeclaration(null, 'C', null, [invocation]) |
| ]); |
| _resolveInClass(invocation, subclass); |
| expect(invocation.staticElement, superConstructor); |
| expect( |
| (invocation.argumentList.arguments[0] as NamedExpression) |
| .name |
| .label |
| .staticElement, |
| same(parameter)); |
| _listener.assertNoErrors(); |
| } |
| |
| /** |
| * Create and return the resolver used by the tests. |
| */ |
| void _createResolver() { |
| InternalAnalysisContext context = AnalysisContextFactory.contextWithCore( |
| resourceProvider: resourceProvider); |
| _typeProvider = context.typeProvider; |
| |
| var inheritance = new InheritanceManager2(context.typeSystem); |
| Source source = new FileSource(getFile("/test.dart")); |
| CompilationUnitElementImpl unit = new CompilationUnitElementImpl(); |
| unit.librarySource = unit.source = source; |
| _definingLibrary = ElementFactory.library(context, "test"); |
| _definingLibrary.definingCompilationUnit = unit; |
| _visitor = new ResolverVisitor( |
| inheritance, _definingLibrary, source, _typeProvider, _listener, |
| featureSet: FeatureSet.forTesting(), |
| nameScope: new LibraryScope(_definingLibrary)); |
| _resolver = _visitor.elementResolver; |
| } |
| |
| /** |
| * Return the element associated with the label of [statement] after the |
| * resolver has resolved it. [labelElement] is the label element to be |
| * defined in the statement's label scope, and [labelTarget] is the statement |
| * the label resolves to. |
| */ |
| Element _resolveBreak(BreakStatement statement, LabelElementImpl labelElement, |
| Statement labelTarget) { |
| _resolveStatement(statement, labelElement, labelTarget); |
| return statement.label.staticElement; |
| } |
| |
| /** |
| * Return the element associated with the label [statement] after the |
| * resolver has resolved it. [labelElement] is the label element to be |
| * defined in the statement's label scope, and [labelTarget] is the AST node |
| * the label resolves to. |
| * |
| * @param statement the statement to be resolved |
| * @param labelElement the label element to be defined in the statement's label scope |
| * @return the element to which the statement's label was resolved |
| */ |
| Element _resolveContinue(ContinueStatement statement, |
| LabelElementImpl labelElement, AstNode labelTarget) { |
| _resolveStatement(statement, labelElement, labelTarget); |
| return statement.label.staticElement; |
| } |
| |
| /** |
| * Return the element associated with the given identifier after the resolver has resolved the |
| * identifier. |
| * |
| * @param node the expression to be resolved |
| * @param definedElements the elements that are to be defined in the scope in which the element is |
| * being resolved |
| * @return the element to which the expression was resolved |
| */ |
| Element _resolveIdentifier(Identifier node, [List<Element> definedElements]) { |
| _resolveNode(node, definedElements); |
| return node.staticElement; |
| } |
| |
| /** |
| * Return the element associated with the given identifier after the resolver has resolved the |
| * identifier. |
| * |
| * @param node the expression to be resolved |
| * @param enclosingClass the element representing the class enclosing the identifier |
| * @return the element to which the expression was resolved |
| */ |
| void _resolveInClass(AstNode node, ClassElement enclosingClass) { |
| Scope outerScope = _visitor.nameScope; |
| try { |
| _visitor.enclosingClass = enclosingClass; |
| EnclosedScope innerScope = new ClassScope( |
| new TypeParameterScope(outerScope, enclosingClass), enclosingClass); |
| _visitor.nameScope = innerScope; |
| node.accept(_resolver); |
| } finally { |
| _visitor.enclosingClass = null; |
| _visitor.nameScope = outerScope; |
| } |
| } |
| |
| /** |
| * Return the element associated with the given expression after the resolver has resolved the |
| * expression. |
| * |
| * @param node the expression to be resolved |
| * @param definedElements the elements that are to be defined in the scope in which the element is |
| * being resolved |
| * @return the element to which the expression was resolved |
| */ |
| Element _resolveIndexExpression(IndexExpression node, |
| [List<Element> definedElements]) { |
| _resolveNode(node, definedElements); |
| return node.staticElement; |
| } |
| |
| /** |
| * Return the element associated with the given identifier after the resolver has resolved the |
| * identifier. |
| * |
| * @param node the expression to be resolved |
| * @param definedElements the elements that are to be defined in the scope in which the element is |
| * being resolved |
| * @return the element to which the expression was resolved |
| */ |
| void _resolveNode(AstNode node, [List<Element> definedElements]) { |
| Scope outerScope = _visitor.nameScope; |
| try { |
| EnclosedScope innerScope = new EnclosedScope(outerScope); |
| if (definedElements != null) { |
| for (Element element in definedElements) { |
| innerScope.define(element); |
| } |
| } |
| _visitor.nameScope = innerScope; |
| node.accept(_resolver); |
| } finally { |
| _visitor.nameScope = outerScope; |
| } |
| } |
| |
| /** |
| * Return the element associated with the label of the given statement after the resolver has |
| * resolved the statement. |
| * |
| * @param statement the statement to be resolved |
| * @param labelElement the label element to be defined in the statement's label scope |
| * @return the element to which the statement's label was resolved |
| */ |
| void _resolveStatement( |
| Statement statement, LabelElementImpl labelElement, AstNode labelTarget) { |
| LabelScope outerScope = _visitor.labelScope; |
| try { |
| LabelScope innerScope; |
| if (labelElement == null) { |
| innerScope = outerScope; |
| } else { |
| innerScope = new LabelScope( |
| outerScope, labelElement.name, labelTarget, labelElement); |
| } |
| _visitor.labelScope = innerScope; |
| statement.accept(_resolver); |
| } finally { |
| _visitor.labelScope = outerScope; |
| } |
| } |
| } |
| |
| @reflectiveTest |
| class PreviewDart2Test extends ResolverTestCase { |
| @override |
| void setUp() { |
| AnalysisOptionsImpl options = new AnalysisOptionsImpl(); |
| resetWith(options: options); |
| } |
| |
| /** |
| * Tests and verifies that even with a explicit 'new' keyword, the |
| * construction of the InstanceCreationExpression node with types and elements |
| * is all correct. |
| */ |
| test_visitMethodInvocations_explicit() async { |
| String code = ''' |
| class A { |
| A() {} |
| } |
| main() { |
| new A(); |
| } |
| '''; |
| CompilationUnit unit = await resolveSource(code); |
| var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main'); |
| |
| ExpressionStatement statement = statements[0]; |
| InstanceCreationExpression creation = statement.expression; |
| |
| expect(creation.staticElement, isConstructorElement); |
| expect(creation.staticType, isNotNull); |
| |
| expect(creation.constructorName.staticElement, isConstructorElement); |
| |
| expect(creation.constructorName.type.type, isNotNull); |
| expect(creation.constructorName.type.name.staticElement, isClassElement); |
| |
| expect(creation.constructorName.name, isNull); |
| } |
| |
| /** |
| * Test that the call to a constructor with an implicit unnamed constructor is |
| * re-written as an InstanceCreationExpression AST node from a |
| * MethodInvocation. |
| * |
| * C() |
| */ |
| test_visitMethodInvocations_implicit() async { |
| String code = ''' |
| class A { |
| A(a, {b}) {} |
| } |
| main() { |
| A(0, b: 1); |
| } |
| '''; |
| CompilationUnit unit = await resolveSource(code); |
| var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main'); |
| |
| ExpressionStatement statement = statements[0]; |
| InstanceCreationExpression creation = statement.expression; |
| ConstructorElement constructor = creation.staticElement; |
| |
| expect(constructor, isConstructorElement); |
| expect(creation.staticType, isNotNull); |
| |
| expect(creation.constructorName.staticElement, constructor); |
| |
| expect(creation.constructorName.type.type, isNotNull); |
| expect(creation.constructorName.type.name.staticElement, isClassElement); |
| |
| expect(creation.constructorName.name, isNull); |
| |
| List<Expression> arguments = creation.argumentList.arguments; |
| Expression argumentA = arguments[0]; |
| expect(argumentA.staticParameterElement, constructor.parameters[0]); |
| NamedExpression argumentB = arguments[1]; |
| expect(argumentB.name.label.staticElement, constructor.parameters[1]); |
| } |
| |
| /** |
| * Test that the call to a constructor with an implicit unnamed constructor is |
| * re-written as an InstanceCreationExpression AST node from a |
| * MethodInvocation. |
| * |
| * C(), where class C has no constructors |
| */ |
| test_visitMethodInvocations_implicit_implicit() async { |
| String code = ''' |
| class A {} |
| main() { |
| A(); |
| } |
| '''; |
| CompilationUnit unit = await resolveSource(code); |
| var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main'); |
| |
| ExpressionStatement statement = statements[0]; |
| InstanceCreationExpression creation = statement.expression; |
| ConstructorElement constructor = creation.staticElement; |
| |
| expect(constructor, isConstructorElement); |
| expect(creation.staticType, isNotNull); |
| |
| expect(creation.constructorName.staticElement, constructor); |
| |
| expect(creation.constructorName.type.type, isNotNull); |
| expect(creation.constructorName.type.name.staticElement, isClassElement); |
| |
| expect(creation.constructorName.name, isNull); |
| |
| expect(creation.argumentList.arguments, isEmpty); |
| } |
| |
| /** |
| * Test that the call to a constructor with an implicit named constructor is |
| * re-written as an InstanceCreationExpression AST node from a |
| * MethodInvocation. |
| * |
| * C.n() |
| */ |
| test_visitMethodInvocations_implicit_named() async { |
| String code = ''' |
| class A { |
| A.named() {} |
| } |
| main() { |
| A.named(); |
| } |
| '''; |
| CompilationUnit unit = await resolveSource(code); |
| var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main'); |
| |
| ExpressionStatement statement = statements[0]; |
| InstanceCreationExpression creation = statement.expression; |
| ConstructorElement constructor = creation.staticElement; |
| |
| expect(constructor, isConstructorElement); |
| expect(creation.staticType, isNotNull); |
| |
| expect(creation.constructorName.staticElement, constructor); |
| |
| expect(creation.constructorName.type.type, isNotNull); |
| expect(creation.constructorName.type.name.staticElement, isClassElement); |
| |
| expect(creation.constructorName.name.staticElement, constructor); |
| } |
| |
| /** |
| * Test that the call to a constructor with a prefixed implicit constructor is |
| * re-written as an InstanceCreationExpression AST node from a |
| * MethodInvocation. |
| * |
| * p.C() |
| */ |
| test_visitMethodInvocations_implicit_prefixed() async { |
| addNamedSource("/fileOne.dart", r''' |
| class A { |
| A() {} |
| } |
| '''); |
| String code = ''' |
| import 'fileOne.dart' as one; |
| |
| main() { |
| one.A(); |
| } |
| '''; |
| CompilationUnit unit = await resolveSource(code); |
| var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main'); |
| |
| ExpressionStatement statement = statements[0]; |
| InstanceCreationExpression creation = statement.expression; |
| ConstructorElement constructor = creation.staticElement; |
| |
| expect(constructor, isConstructorElement); |
| expect(creation.staticType, isNotNull); |
| |
| expect(creation.constructorName.staticElement, constructor); |
| |
| expect(creation.constructorName.type.type, isNotNull); |
| expect(creation.constructorName.type.name.staticElement, isClassElement); |
| |
| expect(creation.constructorName.name, isNull); |
| } |
| |
| /** |
| * Test that the call to a constructor with a prefixed implicit named constructor is |
| * re-written as an InstanceCreationExpression AST node from a |
| * MethodInvocation. |
| * |
| * p.C.n() |
| */ |
| test_visitMethodInvocations_implicit_prefixed_named() async { |
| addNamedSource("/fileOne.dart", r''' |
| class A { |
| A.named(a, {b}) {} |
| } |
| '''); |
| String code = ''' |
| import 'fileOne.dart' as one; |
| main() { |
| one.A.named(0, b: 1); |
| } |
| '''; |
| CompilationUnit unit = await resolveSource(code); |
| var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main'); |
| |
| ExpressionStatement statement = statements[0]; |
| InstanceCreationExpression creation = statement.expression; |
| ConstructorElement constructor = creation.staticElement; |
| |
| expect(constructor, isConstructorElement); |
| expect(creation.staticType, isNotNull); |
| |
| expect(creation.constructorName.staticElement, constructor); |
| |
| expect(creation.constructorName.type.type, isNotNull); |
| expect(creation.constructorName.type.name.staticElement, isClassElement); |
| |
| expect(creation.constructorName.name.staticElement, constructor); |
| |
| List<Expression> arguments = creation.argumentList.arguments; |
| Expression argumentA = arguments[0]; |
| expect(argumentA.staticParameterElement, constructor.parameters[0]); |
| NamedExpression argumentB = arguments[1]; |
| expect(argumentB.name.label.staticElement, constructor.parameters[1]); |
| } |
| |
| /** |
| * Test that the call to a constructor with a prefixed implicit constructor is |
| * re-written as an InstanceCreationExpression AST node from a |
| * MethodInvocation. |
| * |
| * p.C<>() |
| */ |
| test_visitMethodInvocations_implicit_prefixed_typeArgs() async { |
| addNamedSource("/fileOne.dart", r''' |
| class A<T> { |
| final T x; |
| A(this.x) {} |
| } |
| '''); |
| String code = ''' |
| import 'fileOne.dart' as one; |
| |
| main() { |
| one.A<int>(42); |
| } |
| '''; |
| CompilationUnit unit = await resolveSource(code); |
| var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main'); |
| |
| ExpressionStatement statement = statements[0]; |
| InstanceCreationExpression creation = statement.expression; |
| ConstructorElement constructor = creation.staticElement; |
| |
| expect(constructor, isConstructorElement); |
| expect(creation.staticType, isNotNull); |
| |
| expect(creation.constructorName.staticElement, constructor); |
| |
| expect(creation.constructorName.type.type, isNotNull); |
| expect(creation.constructorName.type.name.staticElement, isClassElement); |
| |
| expect(creation.constructorName.name, isNull); |
| } |
| |
| /** |
| * Test that the call to a constructor with an implicit unnamed constructor is |
| * re-written as an InstanceCreationExpression AST node from a |
| * MethodInvocation. |
| * |
| * C<>() |
| */ |
| test_visitMethodInvocations_implicit_typeArgs() async { |
| String code = ''' |
| class A<T> { |
| final T x; |
| A(this.x) {} |
| } |
| main() { |
| A<int>(42); |
| } |
| '''; |
| CompilationUnit unit = await resolveSource(code); |
| var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main'); |
| |
| ExpressionStatement statement = statements[0]; |
| InstanceCreationExpression creation = statement.expression; |
| ConstructorElement constructor = creation.staticElement; |
| |
| expect(constructor, isConstructorElement); |
| expect(creation.staticType, isNotNull); |
| |
| expect(creation.constructorName.staticElement, constructor); |
| |
| expect(creation.constructorName.type.type, isNotNull); |
| expect(creation.constructorName.type.name.staticElement, isClassElement); |
| |
| expect(creation.constructorName.name, isNull); |
| } |
| |
| test_visitMethodInvocations_importPrefix_function() async { |
| String code = ''' |
| import 'dart:math' as ma; |
| main() { |
| ma.max(1, 2); // marker |
| } |
| '''; |
| CompilationUnit unit = await resolveSource(code); |
| var statements = AstFinder.getStatementsInTopLevelFunction(unit, 'main'); |
| |
| ExpressionStatement statement = statements[0]; |
| MethodInvocation invocation = statement.expression; |
| |
| SimpleIdentifier prefix = invocation.target; |
| expect(prefix.staticElement, isPrefixElement); |
| |
| expect(invocation.methodName.name, 'max'); |
| } |
| |
| /** |
| * Test that the call to a static method will not be re-written as a |
| * InstanceCreationExpression AST node. |
| */ |
| test_visitMethodInvocations_not_implicit_constructor() async { |
| String code = ''' |
| class A { |
| static staticMethod() {} |
| } |
| main() { |
| A.staticMethod(); // marker |
| } |
| '''; |
| CompilationUnit unit = await resolveSource(code); |
| AstNode node = findMarkedIdentifier(code, unit, "(); // marker"); |
| assert(node.parent is MethodInvocation); |
| } |
| } |