/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.engine.resolver; import com.google.dart.engine.ast.AssignmentExpression; import com.google.dart.engine.ast.Block; import com.google.dart.engine.ast.BlockFunctionBody; import com.google.dart.engine.ast.ClassDeclaration; import com.google.dart.engine.ast.CompilationUnit; import com.google.dart.engine.ast.CompilationUnitMember; import com.google.dart.engine.ast.Expression; import com.google.dart.engine.ast.ExpressionStatement; import com.google.dart.engine.ast.FunctionBody; import com.google.dart.engine.ast.FunctionTypeAlias; import com.google.dart.engine.ast.MethodDeclaration; import com.google.dart.engine.ast.MethodInvocation; import com.google.dart.engine.ast.NodeList; import com.google.dart.engine.ast.SimpleIdentifier; import com.google.dart.engine.ast.Statement; import com.google.dart.engine.ast.TopLevelVariableDeclaration; import com.google.dart.engine.ast.visitor.RecursiveAstVisitor; import com.google.dart.engine.context.AnalysisException; import com.google.dart.engine.element.ClassElement; import com.google.dart.engine.element.CompilationUnitElement; import com.google.dart.engine.element.ConstructorElement; import com.google.dart.engine.element.Element; import com.google.dart.engine.element.ElementAnnotation; import com.google.dart.engine.element.FieldElement; import com.google.dart.engine.element.FunctionElement; import com.google.dart.engine.element.FunctionTypeAliasElement; import com.google.dart.engine.element.LibraryElement; import com.google.dart.engine.element.MethodElement; import com.google.dart.engine.element.ParameterElement; import com.google.dart.engine.element.PropertyAccessorElement; import com.google.dart.engine.element.PropertyInducingElement; import com.google.dart.engine.error.StaticTypeWarningCode; import com.google.dart.engine.error.StaticWarningCode; import com.google.dart.engine.source.Source; import com.google.dart.engine.type.FunctionType; import com.google.dart.engine.type.Type; public class SimpleResolverTest extends ResolverTestCase { public void fail_staticInvocation() throws Exception { Source source = addSource(createSource(// "class A {", " static int get g => (a,b) => 0;", "}", "class B {", " f() {", " A.g(1,0);", " }", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_argumentResolution_required_matching() throws Exception { Source source = addSource(createSource(// "class A {", " void f() {", " g(1, 2, 3);", " }", " void g(a, b, c) {}", "}")); validateArgumentResolution(source, 0, 1, 2); } public void test_argumentResolution_required_tooFew() throws Exception { Source source = addSource(createSource(// "class A {", " void f() {", " g(1, 2);", " }", " void g(a, b, c) {}", "}")); validateArgumentResolution(source, 0, 1); } public void test_argumentResolution_required_tooMany() throws Exception { Source source = addSource(createSource(// "class A {", " void f() {", " g(1, 2, 3);", " }", " void g(a, b) {}", "}")); validateArgumentResolution(source, 0, 1, -1); } public void test_argumentResolution_requiredAndNamed_extra() throws Exception { Source source = addSource(createSource(// "class A {", " void f() {", " g(1, 2, c: 3, d: 4);", " }", " void g(a, b, {c}) {}", "}")); validateArgumentResolution(source, 0, 1, 2, -1); } public void test_argumentResolution_requiredAndNamed_matching() throws Exception { Source source = addSource(createSource(// "class A {", " void f() {", " g(1, 2, c: 3);", " }", " void g(a, b, {c}) {}", "}")); validateArgumentResolution(source, 0, 1, 2); } public void test_argumentResolution_requiredAndNamed_missing() throws Exception { Source source = addSource(createSource(// "class A {", " void f() {", " g(1, 2, d: 3);", " }", " void g(a, b, {c, d}) {}", "}")); validateArgumentResolution(source, 0, 1, 3); } public void test_argumentResolution_requiredAndPositional_fewer() throws Exception { Source source = addSource(createSource(// "class A {", " void f() {", " g(1, 2, 3);", " }", " void g(a, b, [c, d]) {}", "}")); validateArgumentResolution(source, 0, 1, 2); } public void test_argumentResolution_requiredAndPositional_matching() throws Exception { Source source = addSource(createSource(// "class A {", " void f() {", " g(1, 2, 3, 4);", " }", " void g(a, b, [c, d]) {}", "}")); validateArgumentResolution(source, 0, 1, 2, 3); } public void test_argumentResolution_requiredAndPositional_more() throws Exception { Source source = addSource(createSource(// "class A {", " void f() {", " g(1, 2, 3, 4);", " }", " void g(a, b, [c]) {}", "}")); validateArgumentResolution(source, 0, 1, 2, -1); } public void test_argumentResolution_setter_propagated() throws Exception { Source source = addSource(createSource(// "main() {", " var a = new A();", " a.sss = 0;", "}", "class A {", " set sss(x) {}", "}")); LibraryElement library = resolve(source); CompilationUnitElement unit = library.getDefiningCompilationUnit(); // find "a.sss = 0" AssignmentExpression assignment; { FunctionElement mainElement = unit.getFunctions()[0]; FunctionBody mainBody = mainElement.getNode().getFunctionExpression().getBody(); Statement statement = ((BlockFunctionBody) mainBody).getBlock().getStatements().get(1); ExpressionStatement expressionStatement = (ExpressionStatement) statement; assignment = (AssignmentExpression) expressionStatement.getExpression(); } // get parameter Expression rhs = assignment.getRightHandSide(); assertNull(rhs.getStaticParameterElement()); ParameterElement parameter = rhs.getPropagatedParameterElement(); assertNotNull(parameter); assertEquals("x", parameter.getDisplayName()); // validate ClassElement classA = unit.getTypes()[0]; PropertyAccessorElement setter = classA.getAccessors()[0]; assertSame(parameter, setter.getParameters()[0]); } public void test_argumentResolution_setter_propagated_propertyAccess() throws Exception { Source source = addSource(createSource(// "main() {", " var a = new A();", " a.b.sss = 0;", "}", "class A {", " B b = new B();", "}", "class B {", " set sss(x) {}", "}")); LibraryElement library = resolve(source); CompilationUnitElement unit = library.getDefiningCompilationUnit(); // find "a.b.sss = 0" AssignmentExpression assignment; { FunctionElement mainElement = unit.getFunctions()[0]; FunctionBody mainBody = mainElement.getNode().getFunctionExpression().getBody(); Statement statement = ((BlockFunctionBody) mainBody).getBlock().getStatements().get(1); ExpressionStatement expressionStatement = (ExpressionStatement) statement; assignment = (AssignmentExpression) expressionStatement.getExpression(); } // get parameter Expression rhs = assignment.getRightHandSide(); assertNull(rhs.getStaticParameterElement()); ParameterElement parameter = rhs.getPropagatedParameterElement(); assertNotNull(parameter); assertEquals("x", parameter.getDisplayName()); // validate ClassElement classB = unit.getTypes()[1]; PropertyAccessorElement setter = classB.getAccessors()[0]; assertSame(parameter, setter.getParameters()[0]); } public void test_argumentResolution_setter_static() throws Exception { Source source = addSource(createSource(// "main() {", " A a = new A();", " a.sss = 0;", "}", "class A {", " set sss(x) {}", "}")); LibraryElement library = resolve(source); CompilationUnitElement unit = library.getDefiningCompilationUnit(); // find "a.sss = 0" AssignmentExpression assignment; { FunctionElement mainElement = unit.getFunctions()[0]; FunctionBody mainBody = mainElement.getNode().getFunctionExpression().getBody(); Statement statement = ((BlockFunctionBody) mainBody).getBlock().getStatements().get(1); ExpressionStatement expressionStatement = (ExpressionStatement) statement; assignment = (AssignmentExpression) expressionStatement.getExpression(); } // get parameter Expression rhs = assignment.getRightHandSide(); ParameterElement parameter = rhs.getStaticParameterElement(); assertNotNull(parameter); assertEquals("x", parameter.getDisplayName()); // validate ClassElement classA = unit.getTypes()[0]; PropertyAccessorElement setter = classA.getAccessors()[0]; assertSame(parameter, setter.getParameters()[0]); } public void test_argumentResolution_setter_static_propertyAccess() throws Exception { Source source = addSource(createSource(// "main() {", " A a = new A();", " a.b.sss = 0;", "}", "class A {", " B b = new B();", "}", "class B {", " set sss(x) {}", "}")); LibraryElement library = resolve(source); CompilationUnitElement unit = library.getDefiningCompilationUnit(); // find "a.b.sss = 0" AssignmentExpression assignment; { FunctionElement mainElement = unit.getFunctions()[0]; FunctionBody mainBody = mainElement.getNode().getFunctionExpression().getBody(); Statement statement = ((BlockFunctionBody) mainBody).getBlock().getStatements().get(1); ExpressionStatement expressionStatement = (ExpressionStatement) statement; assignment = (AssignmentExpression) expressionStatement.getExpression(); } // get parameter Expression rhs = assignment.getRightHandSide(); ParameterElement parameter = rhs.getStaticParameterElement(); assertNotNull(parameter); assertEquals("x", parameter.getDisplayName()); // validate ClassElement classB = unit.getTypes()[1]; PropertyAccessorElement setter = classB.getAccessors()[0]; assertSame(parameter, setter.getParameters()[0]); } public void test_class_definesCall() throws Exception { Source source = addSource(createSource(// "class A {", " int call(int x) { return x; }", "}", "int f(A a) {", " return a(0);", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_class_extends_implements() throws Exception { Source source = addSource(createSource(// "class A extends B implements C {}", "class B {}", "class C {}")); resolve(source); assertNoErrors(source); verify(source); } public void test_commentReference_class() throws Exception { Source source = addSource(createSource(// "f() {}", "/** [A] [new A] [A.n] [new A.n] [m] [f] */", "class A {", " A() {}", " A.n() {}", " m() {}", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_commentReference_parameter() throws Exception { Source source = addSource(createSource(// "class A {", " A() {}", " A.n() {}", " /** [e] [f] */", " m(e, f()) {}", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_commentReference_singleLine() throws Exception { Source source = addSource(createSource(// "/// [A]", "class A {}")); resolve(source); assertNoErrors(source); verify(source); } public void test_empty() throws Exception { Source source = addSource(""); resolve(source); assertNoErrors(source); verify(source); } public void test_entryPoint_exported() throws Exception { addNamedSource("/two.dart", createSource(// "library two;", "main() {}")); Source source = addNamedSource("/one.dart", createSource(// "library one;", "export 'two.dart';")); LibraryElement library = resolve(source); assertNotNull(library); FunctionElement main = library.getEntryPoint(); assertNotNull(main); assertNotSame(library, main.getLibrary()); assertNoErrors(source); verify(source); } public void test_entryPoint_local() throws Exception { Source source = addNamedSource("/one.dart", createSource(// "library one;", "main() {}")); LibraryElement library = resolve(source); assertNotNull(library); FunctionElement main = library.getEntryPoint(); assertNotNull(main); assertSame(library, main.getLibrary()); assertNoErrors(source); verify(source); } public void test_entryPoint_none() throws Exception { Source source = addNamedSource("/one.dart", createSource(// "library one;")); LibraryElement library = resolve(source); assertNotNull(library); assertNull(library.getEntryPoint()); assertNoErrors(source); verify(source); } public void test_enum_externalLibrary() throws Exception { resetWithEnum(); addNamedSource("/my_lib.dart", createSource(// "library my_lib;", "enum EEE {A, B, C}")); Source source = addSource(createSource(// "import 'my_lib.dart';", "", "main() {", " EEE e = null;", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_extractedMethodAsConstant() throws Exception { Source source = addSource(createSource(// "abstract class Comparable<T> {", " int compareTo(T other);", " static int compare(Comparable a, Comparable b) => a.compareTo(b);", "}", "class A {", " void sort([compare = Comparable.compare]) {}", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_fieldFormalParameter() throws Exception { Source source = addSource(createSource(// "class A {", " int x;", " A(this.x) {}", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_forEachLoops_nonConflicting() throws Exception { Source source = addSource(createSource(// "f() {", " List list = [1,2,3];", " for (int x in list) {}", " for (int x in list) {}", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_forLoops_nonConflicting() throws Exception { Source source = addSource(createSource(// "f() {", " for (int i = 0; i < 3; i++) {", " }", " for (int i = 0; i < 3; i++) {", " }", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_functionTypeAlias() throws Exception { Source source = addSource(createSource(// "typedef bool P(e);", "class A {", " P p;", " m(e) {", " if (p(e)) {}", " }", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_getterAndSetterWithDifferentTypes() throws Exception { Source source = addSource(createSource(// "class A {", " int get f => 0;", " void set f(String s) {}", "}", "g (A a) {", " a.f = a.f.toString();", "}")); resolve(source); assertErrors(source, StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES); verify(source); } public void test_hasReferenceToSuper() throws Exception { Source source = addSource(createSource(// "class A {}", "class B {toString() => super.toString();}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unit = library.getDefiningCompilationUnit(); assertNotNull(unit); ClassElement[] classes = unit.getTypes(); assertLength(2, classes); assertFalse(classes[0].hasReferenceToSuper()); assertTrue(classes[1].hasReferenceToSuper()); assertNoErrors(source); verify(source); } public void test_import_hide() throws Exception { addNamedSource("lib1.dart", createSource(// "library lib1;", "set foo(value) {}", "class A {}")); addNamedSource("lib2.dart", createSource(// "library lib2;", "set foo(value) {}")); Source source = addNamedSource("lib3.dart", createSource(// "import 'lib1.dart' hide foo;", "import 'lib2.dart';", "", "main() {", " foo = 0;", "}", "A a;")); resolve(source); assertNoErrors(source); verify(source); } public void test_import_prefix() throws Exception { addNamedSource("/two.dart", createSource(// "library two;", "f(int x) {", " return x * x;", "}")); Source source = addNamedSource("/one.dart", createSource(// "library one;", "import 'two.dart' as _two;", "main() {", " _two.f(0);", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_import_spaceInUri() throws Exception { addNamedSource("sub folder/lib.dart", createSource(// "library lib;", "foo() {}")); Source source = addNamedSource("app.dart", createSource(// "import 'sub folder/lib.dart';", "", "main() {", " foo();", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_indexExpression_typeParameters() throws Exception { Source source = addSource(createSource(// "f() {", " List<int> a;", " a[0];", " List<List<int>> b;", " b[0][0];", " List<List<List<int>>> c;", " c[0][0][0];", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_indexExpression_typeParameters_invalidAssignmentWarning() throws Exception { Source source = addSource(createSource(// "f() {", " List<List<int>> b;", " b[0][0] = 'hi';", "}")); resolve(source); assertErrors(source, StaticTypeWarningCode.INVALID_ASSIGNMENT); verify(source); } public void test_indirectOperatorThroughCall() throws Exception { Source source = addSource(createSource(// "class A {", " B call() { return new B(); }", "}", "", "class B {", " int operator [](int i) { return i; }", "}", "", "A f = new A();", "", "g(int x) {}", "", "main() {", " g(f()[0]);", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_invoke_dynamicThroughGetter() throws Exception { Source source = addSource(createSource(// "class A {", " List get X => [() => 0];", " m(A a) {", " X.last;", " }", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_isValidMixin_badSuperclass() throws Exception { Source source = addSource(createSource(// "class A extends B {}", "class B {}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unit = library.getDefiningCompilationUnit(); assertNotNull(unit); ClassElement[] classes = unit.getTypes(); assertLength(2, classes); assertFalse(classes[0].isValidMixin()); assertNoErrors(source); verify(source); } public void test_isValidMixin_constructor() throws Exception { Source source = addSource(createSource(// "class A {", " A() {}", "}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unit = library.getDefiningCompilationUnit(); assertNotNull(unit); ClassElement[] classes = unit.getTypes(); assertLength(1, classes); assertFalse(classes[0].isValidMixin()); assertNoErrors(source); verify(source); } public void test_isValidMixin_super() throws Exception { Source source = addSource(createSource(// "class A {", " toString() {", " return super.toString();", " }", "}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unit = library.getDefiningCompilationUnit(); assertNotNull(unit); ClassElement[] classes = unit.getTypes(); assertLength(1, classes); assertFalse(classes[0].isValidMixin()); assertNoErrors(source); verify(source); } public void test_isValidMixin_valid() throws Exception { Source source = addSource(createSource(// "class A {}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unit = library.getDefiningCompilationUnit(); assertNotNull(unit); ClassElement[] classes = unit.getTypes(); assertLength(1, classes); assertTrue(classes[0].isValidMixin()); assertNoErrors(source); verify(source); } public void test_labels_switch() throws Exception { Source source = addSource(createSource(// "void doSwitch(int target) {", " switch (target) {", " l0: case 0:", " continue l1;", " l1: case 1:", " continue l0;", " default:", " continue l1;", " }", "}")); LibraryElement library = resolve(source); assertNotNull(library); assertNoErrors(source); verify(source); } public void test_localVariable_types_invoked() throws Exception { Source source = addSource(createSource(// "const A = null;", "main() {", " var myVar = (int p) => 'foo';", " myVar(42);", "}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnit unit = getAnalysisContext().getResolvedCompilationUnit(source, library); assertNotNull(unit); final boolean[] found = {false}; final AnalysisException[] thrownException = new AnalysisException[1]; unit.accept(new RecursiveAstVisitor<Void>() { @Override public Void visitSimpleIdentifier(SimpleIdentifier node) { if (node.getName().equals("myVar") && node.getParent() instanceof MethodInvocation) { try { found[0] = true; // check static type Type staticType = node.getStaticType(); assertSame(getTypeProvider().getDynamicType(), staticType); // check propagated type FunctionType propagatedType = (FunctionType) node.getPropagatedType(); assertEquals(getTypeProvider().getStringType(), propagatedType.getReturnType()); } catch (AnalysisException e) { thrownException[0] = e; } } return null; } }); if (thrownException[0] != null) { throw new AnalysisException("Exception", thrownException[0]); } assertTrue(found[0]); } public void test_metadata_class() throws Exception { Source source = addSource(createSource(// "const A = null;", "@A class C<A> {}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unitElement = library.getDefiningCompilationUnit(); assertNotNull(unitElement); ClassElement[] classes = unitElement.getTypes(); assertLength(1, classes); ElementAnnotation[] annotations = classes[0].getMetadata(); assertLength(1, annotations); assertNoErrors(source); verify(source); CompilationUnit unit = resolveCompilationUnit(source, library); NodeList<CompilationUnitMember> declarations = unit.getDeclarations(); assertSizeOfList(2, declarations); Element expectedElement = ((TopLevelVariableDeclaration) declarations.get(0)).getVariables().getVariables().get( 0).getName().getStaticElement(); assertInstanceOf(PropertyInducingElement.class, expectedElement); expectedElement = ((PropertyInducingElement) expectedElement).getGetter(); Element actualElement = ((ClassDeclaration) declarations.get(1)).getMetadata().get(0).getName().getStaticElement(); assertSame(expectedElement, actualElement); } public void test_metadata_field() throws Exception { Source source = addSource(createSource(// "const A = null;", "class C {", " @A int f;", "}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unit = library.getDefiningCompilationUnit(); assertNotNull(unit); ClassElement[] classes = unit.getTypes(); assertLength(1, classes); FieldElement field = classes[0].getFields()[0]; ElementAnnotation[] annotations = field.getMetadata(); assertLength(1, annotations); assertNoErrors(source); verify(source); } public void test_metadata_fieldFormalParameter() throws Exception { Source source = addSource(createSource(// "const A = null;", "class C {", " int f;", " C(@A this.f);", "}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unit = library.getDefiningCompilationUnit(); assertNotNull(unit); ClassElement[] classes = unit.getTypes(); assertLength(1, classes); ConstructorElement[] constructors = classes[0].getConstructors(); assertLength(1, constructors); ParameterElement[] parameters = constructors[0].getParameters(); assertLength(1, parameters); ElementAnnotation[] annotations = parameters[0].getMetadata(); assertLength(1, annotations); assertNoErrors(source); verify(source); } public void test_metadata_function() throws Exception { Source source = addSource(createSource(// "const A = null;", "@A f() {}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unit = library.getDefiningCompilationUnit(); assertNotNull(unit); FunctionElement[] functions = unit.getFunctions(); assertLength(1, functions); ElementAnnotation[] annotations = functions[0].getMetadata(); assertLength(1, annotations); assertNoErrors(source); verify(source); } public void test_metadata_functionTypedParameter() throws Exception { Source source = addSource(createSource(// "const A = null;", "f(@A int p(int x)) {}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unit = library.getDefiningCompilationUnit(); assertNotNull(unit); FunctionElement[] functions = unit.getFunctions(); assertLength(1, functions); ParameterElement[] parameters = functions[0].getParameters(); assertLength(1, parameters); ElementAnnotation[] annotations1 = parameters[0].getMetadata(); assertLength(1, annotations1); assertNoErrors(source); verify(source); } public void test_metadata_libraryDirective() throws Exception { Source source = addSource(createSource(// "@A library lib;", "const A = null;")); LibraryElement library = resolve(source); assertNotNull(library); ElementAnnotation[] annotations = library.getMetadata(); assertLength(1, annotations); assertNoErrors(source); verify(source); } public void test_metadata_method() throws Exception { Source source = addSource(createSource(// "const A = null;", "class C {", " @A void m() {}", "}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unit = library.getDefiningCompilationUnit(); assertNotNull(unit); ClassElement[] classes = unit.getTypes(); assertLength(1, classes); MethodElement method = classes[0].getMethods()[0]; ElementAnnotation[] annotations = method.getMetadata(); assertLength(1, annotations); assertNoErrors(source); verify(source); } public void test_metadata_namedParameter() throws Exception { Source source = addSource(createSource(// "const A = null;", "f({@A int p : 0}) {}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unit = library.getDefiningCompilationUnit(); assertNotNull(unit); FunctionElement[] functions = unit.getFunctions(); assertLength(1, functions); ParameterElement[] parameters = functions[0].getParameters(); assertLength(1, parameters); ElementAnnotation[] annotations1 = parameters[0].getMetadata(); assertLength(1, annotations1); assertNoErrors(source); verify(source); } public void test_metadata_positionalParameter() throws Exception { Source source = addSource(createSource(// "const A = null;", "f([@A int p = 0]) {}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unit = library.getDefiningCompilationUnit(); assertNotNull(unit); FunctionElement[] functions = unit.getFunctions(); assertLength(1, functions); ParameterElement[] parameters = functions[0].getParameters(); assertLength(1, parameters); ElementAnnotation[] annotations1 = parameters[0].getMetadata(); assertLength(1, annotations1); assertNoErrors(source); verify(source); } public void test_metadata_simpleParameter() throws Exception { Source source = addSource(createSource(// "const A = null;", "f(@A p1, @A int p2) {}")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unit = library.getDefiningCompilationUnit(); assertNotNull(unit); FunctionElement[] functions = unit.getFunctions(); assertLength(1, functions); ParameterElement[] parameters = functions[0].getParameters(); assertLength(2, parameters); ElementAnnotation[] annotations1 = parameters[0].getMetadata(); assertLength(1, annotations1); ElementAnnotation[] annotations2 = parameters[1].getMetadata(); assertLength(1, annotations2); assertNoErrors(source); verify(source); } public void test_metadata_typedef() throws Exception { Source source = addSource(createSource(// "const A = null;", "@A typedef F<A>();")); LibraryElement library = resolve(source); assertNotNull(library); CompilationUnitElement unitElement = library.getDefiningCompilationUnit(); assertNotNull(unitElement); FunctionTypeAliasElement[] aliases = unitElement.getFunctionTypeAliases(); assertLength(1, aliases); ElementAnnotation[] annotations = aliases[0].getMetadata(); assertLength(1, annotations); assertNoErrors(source); verify(source); CompilationUnit unit = resolveCompilationUnit(source, library); NodeList<CompilationUnitMember> declarations = unit.getDeclarations(); assertSizeOfList(2, declarations); Element expectedElement = ((TopLevelVariableDeclaration) declarations.get(0)).getVariables().getVariables().get( 0).getName().getStaticElement(); assertInstanceOf(PropertyInducingElement.class, expectedElement); expectedElement = ((PropertyInducingElement) expectedElement).getGetter(); Element actualElement = ((FunctionTypeAlias) declarations.get(1)).getMetadata().get(0).getName().getStaticElement(); assertSame(expectedElement, actualElement); } public void test_method_fromMixin() throws Exception { Source source = addSource(createSource(// "class B {", " bar() => 1;", "}", "class A {", " foo() => 2;", "}", "", "class C extends B with A {", " bar() => super.bar();", " foo() => super.foo();", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_method_fromSuperclassMixin() throws Exception { Source source = addSource(createSource(// "class A {", " void m1() {}", "}", "class B extends Object with A {", "}", "class C extends B {", "}", "f(C c) {", " c.m1();", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_methodCascades() throws Exception { Source source = addSource(createSource(// "class A {", " void m1() {}", " void m2() {}", " void m() {", " A a = new A();", " a..m1()", " ..m2();", " }", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_methodCascades_withSetter() throws Exception { Source source = addSource(createSource(// "class A {", " String name;", " void m1() {}", " void m2() {}", " void m() {", " A a = new A();", " a..m1()", " ..name = 'name'", " ..m2();", " }", "}")); resolve(source); // failing with error code: INVOCATION_OF_NON_FUNCTION assertNoErrors(source); verify(source); } public void test_resolveAgainstNull() throws Exception { Source source = addSource(createSource(// "f(var p) {", " return null == p;", "}")); resolve(source); assertNoErrors(source); } public void test_setter_inherited() throws Exception { Source source = addSource(createSource(// "class A {", " int get x => 0;", " set x(int p) {}", "}", "class B extends A {", " int get x => super.x == null ? 0 : super.x;", " int f() => x = 1;", "}")); resolve(source); assertNoErrors(source); verify(source); } public void test_setter_static() throws Exception { Source source = addSource(createSource(// "set s(x) {", "}", "", "main() {", " s = 123;", "}")); resolve(source); assertNoErrors(source); verify(source); } /** * Resolve the given source and verify that the arguments in a specific method invocation were * correctly resolved. * <p> * The source is expected to be source for a compilation unit, the first declaration is expected * to be a class, the first member of which is expected to be a method with a block body, and the * first statement in the body is expected to be an expression statement whose expression is a * method invocation. It is the arguments to that method invocation that are tested. The method * invocation can contain errors. * <p> * The arguments were resolved correctly if the number of expressions in the list matches the * length of the array of indices and if, for each index in the array of indices, the parameter to * which the argument expression was resolved is the parameter in the invoked method's list of * parameters at that index. Arguments that should not be resolved to a parameter because of an * error can be denoted by including a negative index in the array of indices. * * @param source the source to be resolved * @param indices the array of indices used to associate arguments with parameters * @throws Exception if the source could not be resolved or if the structure of the source is not * valid */ private void validateArgumentResolution(Source source, int... indices) throws Exception { LibraryElement library = resolve(source); assertNotNull(library); ClassElement classElement = library.getDefiningCompilationUnit().getTypes()[0]; ParameterElement[] parameters = classElement.getMethods()[1].getParameters(); CompilationUnit unit = resolveCompilationUnit(source, library); assertNotNull(unit); ClassDeclaration classDeclaration = (ClassDeclaration) unit.getDeclarations().get(0); MethodDeclaration methodDeclaration = ((MethodDeclaration) classDeclaration.getMembers().get(0)); Block block = ((BlockFunctionBody) methodDeclaration.getBody()).getBlock(); ExpressionStatement statement = (ExpressionStatement) block.getStatements().get(0); MethodInvocation invocation = (MethodInvocation) statement.getExpression(); NodeList<Expression> arguments = invocation.getArgumentList().getArguments(); int argumentCount = arguments.size(); assertEquals(indices.length, argumentCount); for (int i = 0; i < argumentCount; i++) { Expression argument = arguments.get(i); ParameterElement element = argument.getStaticParameterElement(); int index = indices[i]; if (index < 0) { assertNull(element); } else { assertSame(parameters[index], element); } } } }