| Index: pkg/analyzer2dart/test/identifier_semantics_test.dart
|
| diff --git a/pkg/analyzer2dart/test/identifier_semantics_test.dart b/pkg/analyzer2dart/test/identifier_semantics_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c875427550b797289c8baed729a1770c75b86f91
|
| --- /dev/null
|
| +++ b/pkg/analyzer2dart/test/identifier_semantics_test.dart
|
| @@ -0,0 +1,1432 @@
|
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +import 'package:unittest/unittest.dart';
|
| +import 'package:analyzer/file_system/memory_file_system.dart';
|
| +import 'mock_sdk.dart';
|
| +import 'package:analyzer/src/generated/sdk.dart';
|
| +import 'package:analyzer/file_system/file_system.dart';
|
| +import 'package:analyzer/src/generated/source.dart';
|
| +import 'package:analyzer/src/generated/engine.dart';
|
| +import 'package:analyzer/src/generated/element.dart';
|
| +import 'package:analyzer/src/generated/source_io.dart';
|
| +import 'package:analyzer/analyzer.dart';
|
| +import 'package:analyzer2dart/src/identifier_semantics.dart';
|
| +
|
| +main() {
|
| + test('Call function defined at top level', () {
|
| + Helper helper = new Helper('''
|
| +g() {}
|
| +
|
| +f() {
|
| + g();
|
| +}
|
| +''');
|
| + helper.checkStaticMethodInvocation('g()', null, 'g', true);
|
| + });
|
| +
|
| + test('Call function defined at top level via prefix', () {
|
| + Helper helper = new Helper('''
|
| +import 'lib.dart' as l;
|
| +
|
| +f() {
|
| + l.g();
|
| +}
|
| +''');
|
| + helper.addFile('/lib.dart', '''
|
| +library lib;
|
| +
|
| +g() {}
|
| +''');
|
| + helper.checkStaticMethodInvocation('l.g()', null, 'g', true);
|
| + });
|
| +
|
| + test('Call method defined statically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static g() {}
|
| +
|
| + f() {
|
| + g();
|
| + }
|
| +}
|
| +''');
|
| + helper.checkStaticMethodInvocation('g()', 'A', 'g', true);
|
| + });
|
| +
|
| + test('Call method defined statically in class from outside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static g() {}
|
| +}
|
| +f() {
|
| + A.g();
|
| +}
|
| +''');
|
| + helper.checkStaticMethodInvocation('A.g()', 'A', 'g', true);
|
| + });
|
| +
|
| + test('Call method defined dynamically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + g() {}
|
| +
|
| + f() {
|
| + g();
|
| + }
|
| +}
|
| +''');
|
| + helper.checkDynamicMethodInvocation('g()', null, 'g');
|
| + });
|
| +
|
| + test(
|
| + 'Call method defined dynamically in class from outside class via typed var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + g() {}
|
| +}
|
| +f(A a) {
|
| + a.g();
|
| +}
|
| +''');
|
| + helper.checkDynamicMethodInvocation('a.g()', 'a', 'g');
|
| + });
|
| +
|
| + test(
|
| + 'Call method defined dynamically in class from outside class via typed expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + g() {}
|
| +}
|
| +A h() => null;
|
| +f() {
|
| + h().g();
|
| +}
|
| +''');
|
| + helper.checkDynamicMethodInvocation('h().g()', 'h()', 'g');
|
| + });
|
| +
|
| + test(
|
| + 'Call method defined dynamically in class from outside class via dynamic var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +f(a) {
|
| + a.g();
|
| +}
|
| +''');
|
| + helper.checkDynamicMethodInvocation('a.g()', 'a', 'g');
|
| + });
|
| +
|
| + test(
|
| + 'Call method defined dynamically in class from outside class via dynamic expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +h() => null;
|
| +f() {
|
| + h().g();
|
| +}
|
| +''');
|
| + helper.checkDynamicMethodInvocation('h().g()', 'h()', 'g');
|
| + });
|
| +
|
| + test('Call method defined locally', () {
|
| + Helper helper = new Helper('''
|
| +f() {
|
| + g() {}
|
| + g();
|
| +}
|
| +''');
|
| + helper.checkLocalFunctionInvocation('g()', 'g');
|
| + });
|
| +
|
| + test('Call method undefined at top level', () {
|
| + Helper helper = new Helper('''
|
| +f() {
|
| + g();
|
| +}
|
| +''');
|
| + // Undefined top level invocations are treated as DynamicMethodInvocation.
|
| + // TODO(paulberry): not sure if this is a good idea. In general, when such
|
| + // a call appears inside an instance method, it is dynamic, because "this"
|
| + // might be an instance of a derived class that implements g(). However,
|
| + // in this case, we are not inside an instance method, so we know that the
|
| + // target is undefined.
|
| + helper.checkDynamicMethodInvocation('g()', null, 'g');
|
| + });
|
| +
|
| + test('Call method undefined at top level via prefix', () {
|
| + Helper helper = new Helper('''
|
| +import 'lib.dart' as l;
|
| +
|
| +f() {
|
| + l.g();
|
| +}
|
| +''');
|
| + helper.addFile('/lib.dart', '''
|
| +library lib;
|
| +''');
|
| + // Undefined top level invocations are treated as DynamicMethodInvocation.
|
| + // TODO(paulberry): not sure if this is a good idea, for similar reasons to
|
| + // the case above.
|
| + helper.checkDynamicMethodInvocation('l.g()', null, 'g');
|
| + });
|
| +
|
| + test('Call method undefined statically in class from outside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {}
|
| +
|
| +f() {
|
| + A.g();
|
| +}
|
| +''');
|
| + helper.checkStaticMethodInvocation('A.g()', 'A', 'g', false);
|
| + });
|
| +
|
| + test('Call method undefined dynamically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + f() {
|
| + g();
|
| + }
|
| +}
|
| +''');
|
| + helper.checkDynamicMethodInvocation('g()', null, 'g');
|
| + });
|
| +
|
| + test(
|
| + 'Call method undefined dynamically in class from outside class via typed var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {}
|
| +
|
| +f(A a) {
|
| + a.g();
|
| +}
|
| +''');
|
| + helper.checkDynamicMethodInvocation('a.g()', 'a', 'g');
|
| + });
|
| +
|
| + test(
|
| + 'Call method undefined dynamically in class from outside class via typed expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {}
|
| +
|
| +A h() => null;
|
| +
|
| +f() {
|
| + h().g();
|
| +}
|
| +''');
|
| + helper.checkDynamicMethodInvocation('h().g()', 'h()', 'g');
|
| + });
|
| +
|
| + test('Get variable defined at top level', () {
|
| + Helper helper = new Helper('''
|
| +var x;
|
| +
|
| +f() {
|
| + return x;
|
| +}
|
| +''');
|
| + helper.checkStaticFieldElementRef('x', null, 'x', true, false);
|
| + });
|
| +
|
| + test('Get variable defined at top level via prefix', () {
|
| + Helper helper = new Helper('''
|
| +import 'lib.dart' as l;
|
| +
|
| +f() {
|
| + return l.x;
|
| +}
|
| +''');
|
| + helper.addFile('/lib.dart', '''
|
| +library lib;
|
| +
|
| +var x;
|
| +''');
|
| + helper.checkStaticFieldElementRef('l.x', null, 'x', true, false);
|
| + });
|
| +
|
| + test('Get field defined statically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static var x;
|
| +
|
| + f() {
|
| + return x;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkStaticFieldElementRef('x', 'A', 'x', true, false);
|
| + });
|
| +
|
| + test('Get field defined statically in class from outside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static var x;
|
| +}
|
| +
|
| +f() {
|
| + return A.x;
|
| +}
|
| +''');
|
| + helper.checkStaticFieldElementRef('A.x', 'A', 'x', true, false);
|
| + });
|
| +
|
| + test('Get field defined dynamically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + var x;
|
| +
|
| + f() {
|
| + return x;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('x', null, 'x', true, false);
|
| + });
|
| +
|
| + test(
|
| + 'Get field defined dynamically in class from outside class via typed var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + var x;
|
| +}
|
| +
|
| +f(A a) {
|
| + return a.x;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, false);
|
| + });
|
| +
|
| + test(
|
| + 'Get field defined dynamically in class from outside class via typed expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + var x;
|
| +}
|
| +
|
| +A h() => null;
|
| +
|
| +f() {
|
| + return h().x;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, false);
|
| + });
|
| +
|
| + test(
|
| + 'Get field defined dynamically in class from outside class via dynamic var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +f(a) {
|
| + return a.x;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, false);
|
| + });
|
| +
|
| + test(
|
| + 'Get field defined dynamically in class from outside class via dynamic expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +h() => null;
|
| +
|
| +f() {
|
| + return h().x;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, false);
|
| + });
|
| +
|
| + test('Get variable defined locally', () {
|
| + Helper helper = new Helper('''
|
| +f() {
|
| + var x;
|
| + return x;
|
| +}
|
| +''');
|
| + helper.checkLocalVariableAccess('x', true, false);
|
| + });
|
| +
|
| + test('Get accessor defined at top level', () {
|
| + Helper helper = new Helper('''
|
| +get x => null;
|
| +
|
| +f() {
|
| + return x;
|
| +}
|
| +''');
|
| + helper.checkStaticPropertyAccess('x', null, 'x', true, true, false);
|
| + });
|
| +
|
| + test('Get accessor defined at top level via prefix', () {
|
| + Helper helper = new Helper('''
|
| +import 'lib.dart' as l;
|
| +
|
| +f() {
|
| + return l.x;
|
| +}
|
| +''');
|
| + helper.addFile('/lib.dart', '''
|
| +library lib;
|
| +
|
| +get x => null;
|
| +''');
|
| + helper.checkStaticPropertyAccess('l.x', null, 'x', true, true, false);
|
| + });
|
| +
|
| + test('Get accessor defined statically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static get x => null;
|
| +
|
| + f() {
|
| + return x;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkStaticPropertyAccess('x', 'A', 'x', true, true, false);
|
| + });
|
| +
|
| + test('Get accessor defined statically in class from outside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static get x => null;
|
| +}
|
| +
|
| +f() {
|
| + return A.x;
|
| +}
|
| +''');
|
| + helper.checkStaticPropertyAccess('A.x', 'A', 'x', true, true, false);
|
| + });
|
| +
|
| + test('Get accessor defined dynamically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + get x => null;
|
| +
|
| + f() {
|
| + return x;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('x', null, 'x', true, false);
|
| + });
|
| +
|
| + test(
|
| + 'Get accessor defined dynamically in class from outside class via typed var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + get x => null;
|
| +}
|
| +
|
| +f(A a) {
|
| + return a.x;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, false);
|
| + });
|
| +
|
| + test(
|
| + 'Get accessor defined dynamically in class from outside class via typed expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + get x => null;
|
| +}
|
| +
|
| +A h() => null;
|
| +
|
| +f() {
|
| + return h().x;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, false);
|
| + });
|
| +
|
| + test(
|
| + 'Get accessor defined dynamically in class from outside class via dynamic var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +f(a) {
|
| + return a.x;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, false);
|
| + });
|
| +
|
| + test(
|
| + 'Get accessor defined dynamically in class from outside class via dynamic expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +h() => null;
|
| +
|
| +f() {
|
| + return h().x;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, false);
|
| + });
|
| +
|
| + test('Get accessor undefined at top level', () {
|
| + Helper helper = new Helper('''
|
| +f() {
|
| + return x;
|
| +}
|
| +''');
|
| + // Undefined top level property accesses are treated as
|
| + // DynamicPropertyAccess. TODO(paulberry): not sure if this is a good
|
| + // idea. In general, when such an access appears inside an instance
|
| + // method, it is dynamic, because "this" might be an instance of a derived
|
| + // class that implements x. However, in this case, we are not inside an
|
| + // instance method, so we know that the target is undefined.
|
| + helper.checkDynamicPropertyAccess('x', null, 'x', true, false);
|
| + });
|
| +
|
| + test('Get accessor undefined at top level via prefix', () {
|
| + Helper helper = new Helper('''
|
| +import 'lib.dart' as l;
|
| +
|
| +f() {
|
| + return l.x;
|
| +}
|
| +''');
|
| + helper.addFile('/lib.dart', '''
|
| +library lib;
|
| +''');
|
| + // Undefined top level property accesses are treated as
|
| + // DynamicPropertyAccess. TODO(paulberry): not sure if this is a good
|
| + // idea, for similar reasons to the case above.
|
| + helper.checkDynamicPropertyAccess('l.x', null, 'x', true, false);
|
| + });
|
| +
|
| + test('Get accessor undefined statically in class from outside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {}
|
| +
|
| +f() {
|
| + return A.x;
|
| +}
|
| +''');
|
| + helper.checkStaticPropertyAccess('A.x', 'A', 'x', false, true, false);
|
| + });
|
| +
|
| + test('Get accessor undefined dynamically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + f() {
|
| + return x;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('x', null, 'x', true, false);
|
| + });
|
| +
|
| + test(
|
| + 'Get accessor undefined dynamically in class from outside class via typed var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {}
|
| +
|
| +f(A a) {
|
| + return a.x;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, false);
|
| + });
|
| +
|
| + test(
|
| + 'Get accessor undefined dynamically in class from outside class via typed expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {}
|
| +
|
| +A h() => null;
|
| +
|
| +f() {
|
| + return h().x;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, false);
|
| + });
|
| +
|
| + test('Set variable defined at top level', () {
|
| + Helper helper = new Helper('''
|
| +var x;
|
| +
|
| +f() {
|
| + x = 1;
|
| +}
|
| +''');
|
| + helper.checkStaticFieldElementRef('x', null, 'x', false, true);
|
| + });
|
| +
|
| + test('Set variable defined at top level via prefix', () {
|
| + Helper helper = new Helper('''
|
| +import 'lib.dart' as l;
|
| +
|
| +f() {
|
| + l.x = 1;
|
| +}
|
| +''');
|
| + helper.addFile('/lib.dart', '''
|
| +library lib;
|
| +
|
| +var x;
|
| +''');
|
| + helper.checkStaticFieldElementRef('l.x', null, 'x', false, true);
|
| + });
|
| +
|
| + test('Set field defined statically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static var x;
|
| +
|
| + f() {
|
| + x = 1;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkStaticFieldElementRef('x', 'A', 'x', false, true);
|
| + });
|
| +
|
| + test('Set field defined statically in class from outside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static var x;
|
| +}
|
| +
|
| +f() {
|
| + A.x = 1;
|
| +}
|
| +''');
|
| + helper.checkStaticFieldElementRef('A.x', 'A', 'x', false, true);
|
| + });
|
| +
|
| + test('Set field defined dynamically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + var x;
|
| +
|
| + f() {
|
| + x = 1;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('x', null, 'x', false, true);
|
| + });
|
| +
|
| + test(
|
| + 'Set field defined dynamically in class from outside class via typed var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + var x;
|
| +}
|
| +
|
| +f(A a) {
|
| + a.x = 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('a.x', 'a', 'x', false, true);
|
| + });
|
| +
|
| + test(
|
| + 'Set field defined dynamically in class from outside class via typed expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + var x;
|
| +}
|
| +
|
| +A h() => null;
|
| +
|
| +f() {
|
| + h().x = 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', false, true);
|
| + });
|
| +
|
| + test('Set variable defined locally', () {
|
| + Helper helper = new Helper('''
|
| +f() {
|
| + var x;
|
| + x = 1;
|
| +}
|
| +''');
|
| + helper.checkLocalVariableAccess('x', false, true);
|
| + });
|
| +
|
| + test('Set accessor defined at top level', () {
|
| + Helper helper = new Helper('''
|
| +set x(value) {};
|
| +
|
| +f() {
|
| + x = 1;
|
| +}
|
| +''');
|
| + helper.checkStaticPropertyAccess('x', null, 'x', true, false, true);
|
| + });
|
| +
|
| + test('Set accessor defined at top level via prefix', () {
|
| + Helper helper = new Helper('''
|
| +import 'lib.dart' as l;
|
| +
|
| +f() {
|
| + l.x = 1;
|
| +}
|
| +''');
|
| + helper.addFile('/lib.dart', '''
|
| +library lib;
|
| +
|
| +set x(value) {};
|
| +''');
|
| + helper.checkStaticPropertyAccess('l.x', null, 'x', true, false, true);
|
| + });
|
| +
|
| + test('Set accessor defined statically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static set x(value) {}
|
| +
|
| + f() {
|
| + x = 1;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkStaticPropertyAccess('x', 'A', 'x', true, false, true);
|
| + });
|
| +
|
| + test('Set accessor defined statically in class from outside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static set x(value) {}
|
| +}
|
| +
|
| +f() {
|
| + A.x = 1;
|
| +}
|
| +''');
|
| + helper.checkStaticPropertyAccess('A.x', 'A', 'x', true, false, true);
|
| + });
|
| +
|
| + test('Set accessor defined dynamically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + set x(value) {}
|
| +
|
| + f() {
|
| + x = 1;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('x', null, 'x', false, true);
|
| + });
|
| +
|
| + test(
|
| + 'Set accessor defined dynamically in class from outside class via typed var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + set x(value) {}
|
| +}
|
| +
|
| +f(A a) {
|
| + a.x = 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('a.x', 'a', 'x', false, true);
|
| + });
|
| +
|
| + test(
|
| + 'Set accessor defined dynamically in class from outside class via typed expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + set x(value) {}
|
| +}
|
| +
|
| +A h() => null;
|
| +
|
| +f() {
|
| + h().x = 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', false, true);
|
| + });
|
| +
|
| + test(
|
| + 'Set accessor defined dynamically in class from outside class via dynamic var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +f(a) {
|
| + a.x = 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('a.x', 'a', 'x', false, true);
|
| + });
|
| +
|
| + test(
|
| + 'Set accessor defined dynamically in class from outside class via dynamic expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +h() => null;
|
| +
|
| +f() {
|
| + h().x = 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', false, true);
|
| + });
|
| +
|
| + test('Set accessor undefined at top level', () {
|
| + Helper helper = new Helper('''
|
| +f() {
|
| + x = 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('x', null, 'x', false, true);
|
| + });
|
| +
|
| + test('Set accessor undefined at top level via prefix', () {
|
| + Helper helper = new Helper('''
|
| +import 'lib.dart' as l;
|
| +
|
| +f() {
|
| + l.x = 1;
|
| +}
|
| +''');
|
| + helper.addFile('/lib.dart', '''
|
| +library lib;
|
| +''');
|
| + helper.checkDynamicPropertyAccess('l.x', null, 'x', false, true);
|
| + });
|
| +
|
| + test('Set accessor undefined statically in class from outside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {}
|
| +
|
| +f() {
|
| + A.x = 1;
|
| +}
|
| +''');
|
| + helper.checkStaticPropertyAccess('A.x', 'A', 'x', false, false, true);
|
| + });
|
| +
|
| + test('Set accessor undefined dynamically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + f() {
|
| + x = 1;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('x', null, 'x', false, true);
|
| + });
|
| +
|
| + test(
|
| + 'Set accessor undefined dynamically in class from outside class via typed var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {}
|
| +
|
| +f(A a) {
|
| + a.x = 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('a.x', 'a', 'x', false, true);
|
| + });
|
| +
|
| + test(
|
| + 'Set accessor undefined dynamically in class from outside class via typed expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {}
|
| +
|
| +A h() => null;
|
| +
|
| +f() {
|
| + h().x = 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', false, true);
|
| + });
|
| +
|
| + test('RMW variable defined at top level', () {
|
| + Helper helper = new Helper('''
|
| +var x;
|
| +
|
| +f() {
|
| + x += 1;
|
| +}
|
| +''');
|
| + helper.checkStaticFieldElementRef('x', null, 'x', true, true);
|
| + });
|
| +
|
| + test('RMW variable defined at top level via prefix', () {
|
| + Helper helper = new Helper('''
|
| +import 'lib.dart' as l;
|
| +
|
| +f() {
|
| + l.x += 1;
|
| +}
|
| +''');
|
| + helper.addFile('/lib.dart', '''
|
| +library lib;
|
| +
|
| +var x;
|
| +''');
|
| + helper.checkStaticFieldElementRef('l.x', null, 'x', true, true);
|
| + });
|
| +
|
| + test('RMW field defined statically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static var x;
|
| +
|
| + f() {
|
| + x += 1;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkStaticFieldElementRef('x', 'A', 'x', true, true);
|
| + });
|
| +
|
| + test('RMW field defined statically in class from outside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static var x;
|
| +}
|
| +
|
| +f() {
|
| + A.x += 1;
|
| +}
|
| +''');
|
| + helper.checkStaticFieldElementRef('A.x', 'A', 'x', true, true);
|
| + });
|
| +
|
| + test('RMW field defined dynamically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + var x;
|
| +
|
| + f() {
|
| + x += 1;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('x', null, 'x', true, true);
|
| + });
|
| +
|
| + test(
|
| + 'RMW field defined dynamically in class from outside class via typed var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + var x;
|
| +}
|
| +
|
| +f(A a) {
|
| + a.x += 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, true);
|
| + });
|
| +
|
| + test(
|
| + 'RMW field defined dynamically in class from outside class via typed expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + var x;
|
| +}
|
| +
|
| +A h() => null;
|
| +
|
| +f() {
|
| + h().x += 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, true);
|
| + });
|
| +
|
| + test('RMW variable defined locally', () {
|
| + Helper helper = new Helper('''
|
| +f() {
|
| + var x;
|
| + x += 1;
|
| +}
|
| +''');
|
| + helper.checkLocalVariableAccess('x', true, true);
|
| + });
|
| +
|
| + test('RMW accessor defined at top level', () {
|
| + Helper helper = new Helper('''
|
| +set x(value) {};
|
| +
|
| +f() {
|
| + x += 1;
|
| +}
|
| +''');
|
| + helper.checkStaticPropertyAccess('x', null, 'x', true, true, true);
|
| + });
|
| +
|
| + test('RMW accessor defined at top level via prefix', () {
|
| + Helper helper = new Helper('''
|
| +import 'lib.dart' as l;
|
| +
|
| +f() {
|
| + l.x += 1;
|
| +}
|
| +''');
|
| + helper.addFile('/lib.dart', '''
|
| +library lib;
|
| +
|
| +set x(value) {};
|
| +''');
|
| + helper.checkStaticPropertyAccess('l.x', null, 'x', true, true, true);
|
| + });
|
| +
|
| + test('RMW accessor defined statically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static set x(value) {}
|
| +
|
| + f() {
|
| + x += 1;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkStaticPropertyAccess('x', 'A', 'x', true, true, true);
|
| + });
|
| +
|
| + test('RMW accessor defined statically in class from outside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + static set x(value) {}
|
| +}
|
| +
|
| +f() {
|
| + A.x += 1;
|
| +}
|
| +''');
|
| + helper.checkStaticPropertyAccess('A.x', 'A', 'x', true, true, true);
|
| + });
|
| +
|
| + test('RMW accessor defined dynamically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + set x(value) {}
|
| +
|
| + f() {
|
| + x += 1;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('x', null, 'x', true, true);
|
| + });
|
| +
|
| + test(
|
| + 'RMW accessor defined dynamically in class from outside class via typed var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + set x(value) {}
|
| +}
|
| +
|
| +f(A a) {
|
| + a.x += 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, true);
|
| + });
|
| +
|
| + test(
|
| + 'RMW accessor defined dynamically in class from outside class via typed expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + set x(value) {}
|
| +}
|
| +
|
| +A h() => null;
|
| +
|
| +f() {
|
| + h().x += 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, true);
|
| + });
|
| +
|
| + test(
|
| + 'RMW accessor defined dynamically in class from outside class via dynamic var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +f(a) {
|
| + a.x += 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, true);
|
| + });
|
| +
|
| + test(
|
| + 'RMW accessor defined dynamically in class from outside class via dynamic expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +h() => null;
|
| +
|
| +f() {
|
| + h().x += 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, true);
|
| + });
|
| +
|
| + test('RMW accessor undefined at top level', () {
|
| + Helper helper = new Helper('''
|
| +f() {
|
| + x += 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('x', null, 'x', true, true);
|
| + });
|
| +
|
| + test('RMW accessor undefined at top level via prefix', () {
|
| + Helper helper = new Helper('''
|
| +import 'lib.dart' as l;
|
| +
|
| +f() {
|
| + l.x += 1;
|
| +}
|
| +''');
|
| + helper.addFile('/lib.dart', '''
|
| +library lib;
|
| +''');
|
| + helper.checkDynamicPropertyAccess('l.x', null, 'x', true, true);
|
| + });
|
| +
|
| + test('RMW accessor undefined statically in class from outside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {}
|
| +
|
| +f() {
|
| + A.x += 1;
|
| +}
|
| +''');
|
| + helper.checkStaticPropertyAccess('A.x', 'A', 'x', false, true, true);
|
| + });
|
| +
|
| + test('RMW accessor undefined dynamically in class from inside class', () {
|
| + Helper helper = new Helper('''
|
| +class A {
|
| + f() {
|
| + x += 1;
|
| + }
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('x', null, 'x', true, true);
|
| + });
|
| +
|
| + test(
|
| + 'RMW accessor undefined dynamically in class from outside class via typed var',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {}
|
| +
|
| +f(A a) {
|
| + a.x += 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, true);
|
| + });
|
| +
|
| + test(
|
| + 'RMW accessor undefined dynamically in class from outside class via typed expression',
|
| + () {
|
| + Helper helper = new Helper('''
|
| +class A {}
|
| +
|
| +A h() => null;
|
| +
|
| +f() {
|
| + h().x += 1;
|
| +}
|
| +''');
|
| + helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, true);
|
| + });
|
| +}
|
| +
|
| +class Helper {
|
| + final MemoryResourceProvider provider = new MemoryResourceProvider();
|
| + Source rootSource;
|
| + AnalysisContext context;
|
| +
|
| + Helper(String rootContents) {
|
| + DartSdk sdk = new MockSdk();
|
| + String rootFile = '/root.dart';
|
| + File file = provider.newFile(rootFile, rootContents);
|
| + rootSource = file.createSource();
|
| + context = AnalysisEngine.instance.createAnalysisContext();
|
| + // Set up the source factory.
|
| + List<UriResolver> uriResolvers = [
|
| + new ResourceUriResolver(provider),
|
| + new DartUriResolver(sdk)];
|
| + context.sourceFactory = new SourceFactory(uriResolvers);
|
| + // add the Source
|
| + ChangeSet changeSet = new ChangeSet();
|
| + changeSet.addedSource(rootSource);
|
| + context.applyChanges(changeSet);
|
| + }
|
| +
|
| + void addFile(String path, String contents) {
|
| + provider.newFile(path, contents);
|
| + }
|
| +
|
| + LibraryElement get libraryElement {
|
| + return context.computeLibraryElement(rootSource);
|
| + }
|
| +
|
| + /**
|
| + * Verify that the node represented by [expectedSource] is classified as
|
| + * a static field element reference.
|
| + */
|
| + void checkStaticFieldElementRef(String expectedSource, String expectedClass,
|
| + String expectedName, bool expectedIsRead, bool expectedIsWrite) {
|
| + TestVisitor visitor = new TestVisitor();
|
| + int count = 0;
|
| + visitor.onAccess = (Expression node, AccessSemantics semantics) {
|
| + count++;
|
| + expect(node.toSource(), equals(expectedSource));
|
| + expect(semantics, new isInstanceOf<StaticFieldAccess>());
|
| + if (semantics is StaticFieldAccess) {
|
| + expect(semantics.field.displayName, equals(expectedName));
|
| + if (expectedClass == null) {
|
| + expect(semantics.classElement, isNull);
|
| + } else {
|
| + expect(semantics.classElement, isNotNull);
|
| + expect(semantics.classElement.displayName, equals(expectedClass));
|
| + }
|
| + }
|
| + expect(semantics.isRead, equals(expectedIsRead));
|
| + expect(semantics.isWrite, equals(expectedIsWrite));
|
| + };
|
| + libraryElement.unit.accept(visitor);
|
| + expect(count, equals(1));
|
| + }
|
| +
|
| + /**
|
| + * Verify that the node represented by [expectedSource] is classified as
|
| + * a static property access.
|
| + */
|
| + void checkStaticPropertyAccess(String expectedSource, String expectedClass,
|
| + String expectedName, bool defined, bool expectedIsRead, bool expectedIsWrite) {
|
| + TestVisitor visitor = new TestVisitor();
|
| + int count = 0;
|
| + visitor.onAccess = (Expression node, AccessSemantics semantics) {
|
| + count++;
|
| + expect(node.toSource(), equals(expectedSource));
|
| + expect(semantics, new isInstanceOf<StaticPropertyAccess>());
|
| + if (semantics is StaticPropertyAccess) {
|
| + expect(semantics.propertyName.name, equals(expectedName));
|
| + if (expectedClass == null) {
|
| + expect(semantics.classElement, isNull);
|
| + } else {
|
| + expect(semantics.classElement, isNotNull);
|
| + expect(semantics.classElement.displayName, equals(expectedClass));
|
| + }
|
| + if (defined) {
|
| + expect(semantics.property.displayName, equals(expectedName));
|
| + } else {
|
| + expect(semantics.property, isNull);
|
| + }
|
| + }
|
| + expect(semantics.isRead, equals(expectedIsRead));
|
| + expect(semantics.isWrite, equals(expectedIsWrite));
|
| + };
|
| + libraryElement.unit.accept(visitor);
|
| + expect(count, equals(1));
|
| + }
|
| +
|
| + /**
|
| + * Verify that the node represented by [expectedSource] is classified as
|
| + * a static method invocation.
|
| + */
|
| + void checkStaticMethodInvocation(String expectedSource, String expectedClass,
|
| + String expectedName, bool defined) {
|
| + TestVisitor visitor = new TestVisitor();
|
| + int count = 0;
|
| + visitor.onMethodInvocation =
|
| + (MethodInvocation node, MethodInvocationSemantics semantics) {
|
| + count++;
|
| + expect(node.toSource(), equals(expectedSource));
|
| + expect(semantics, new isInstanceOf<StaticMethodInvocation>());
|
| + if (semantics is StaticMethodInvocation) {
|
| + expect(semantics.methodName.name, equals(expectedName));
|
| + if (expectedClass == null) {
|
| + expect(semantics.classElement, isNull);
|
| + if (defined) {
|
| + expect(
|
| + semantics.methodElement,
|
| + new isInstanceOf<FunctionElement>());
|
| + }
|
| + } else {
|
| + expect(semantics.classElement, isNotNull);
|
| + expect(semantics.classElement.displayName, equals(expectedClass));
|
| + if (defined) {
|
| + expect(semantics.methodElement, new isInstanceOf<MethodElement>());
|
| + }
|
| + }
|
| + if (defined) {
|
| + expect(semantics.methodElement.displayName, equals(expectedName));
|
| + } else {
|
| + expect(semantics.methodElement, isNull);
|
| + }
|
| + }
|
| + };
|
| + libraryElement.unit.accept(visitor);
|
| + expect(count, equals(1));
|
| + }
|
| +
|
| + /**
|
| + * Verify that the node represented by [expectedSource] is classified as
|
| + * a dynamic method invocation.
|
| + */
|
| + void checkDynamicMethodInvocation(String expectedSource,
|
| + String expectedTarget, String expectedName) {
|
| + TestVisitor visitor = new TestVisitor();
|
| + int count = 0;
|
| + visitor.onMethodInvocation =
|
| + (MethodInvocation node, MethodInvocationSemantics semantics) {
|
| + count++;
|
| + expect(node.toSource(), equals(expectedSource));
|
| + expect(semantics, new isInstanceOf<DynamicMethodInvocation>());
|
| + if (semantics is DynamicMethodInvocation) {
|
| + if (expectedTarget == null) {
|
| + expect(semantics.target, isNull);
|
| + } else {
|
| + expect(semantics.target.toSource(), equals(expectedTarget));
|
| + }
|
| + expect(semantics.methodName.name, equals(expectedName));
|
| + }
|
| + };
|
| + libraryElement.unit.accept(visitor);
|
| + expect(count, equals(1));
|
| + }
|
| +
|
| + /**
|
| + * Verify that the node represented by [expectedSource] is classified as
|
| + * a local function invocation.
|
| + */
|
| + void checkLocalFunctionInvocation(String expectedSource,
|
| + String expectedName) {
|
| + TestVisitor visitor = new TestVisitor();
|
| + int count = 0;
|
| + visitor.onMethodInvocation =
|
| + (MethodInvocation node, MethodInvocationSemantics semantics) {
|
| + count++;
|
| + expect(node.toSource(), equals(expectedSource));
|
| + expect(semantics, new isInstanceOf<LocalFunctionInvocation>());
|
| + if (semantics is LocalFunctionInvocation) {
|
| + expect(semantics.functionElement.displayName, equals(expectedName));
|
| + }
|
| + };
|
| + libraryElement.unit.accept(visitor);
|
| + expect(count, equals(1));
|
| + }
|
| +
|
| + /**
|
| + * Verify that the node represented by [expectedSource] is classified as
|
| + * a dynamic property access.
|
| + */
|
| + void checkDynamicPropertyAccess(String expectedSource, String expectedTarget,
|
| + String expectedName, bool expectedIsRead, bool expectedIsWrite) {
|
| + TestVisitor visitor = new TestVisitor();
|
| + int count = 0;
|
| + visitor.onAccess = (Expression node, AccessSemantics semantics) {
|
| + count++;
|
| + expect(node.toSource(), equals(expectedSource));
|
| + expect(semantics, new isInstanceOf<DynamicPropertyAccess>());
|
| + if (semantics is DynamicPropertyAccess) {
|
| + if (expectedTarget == null) {
|
| + expect(semantics.target, isNull);
|
| + } else {
|
| + expect(semantics.target.toSource(), equals(expectedTarget));
|
| + }
|
| + expect(semantics.propertyName.name, equals(expectedName));
|
| + }
|
| + expect(semantics.isRead, equals(expectedIsRead));
|
| + expect(semantics.isWrite, equals(expectedIsWrite));
|
| + };
|
| + libraryElement.unit.accept(visitor);
|
| + expect(count, equals(1));
|
| + }
|
| +
|
| + /**
|
| + * Verify that the node represented by [expectedSource] is classified as
|
| + * a local variable access.
|
| + */
|
| + void checkLocalVariableAccess(String expectedName, bool expectedIsRead,
|
| + bool expectedIsWrite) {
|
| + TestVisitor visitor = new TestVisitor();
|
| + int count = 0;
|
| + visitor.onAccess = (SimpleIdentifier node, AccessSemantics semantics) {
|
| + count++;
|
| + expect(node.name, equals(expectedName));
|
| + expect(semantics, new isInstanceOf<LocalVariableAccess>());
|
| + if (semantics is LocalVariableAccess) {
|
| + LocalVariableElement element = semantics.variable;
|
| + expect(element.name, equals(expectedName));
|
| + }
|
| + expect(semantics.isRead, equals(expectedIsRead));
|
| + expect(semantics.isWrite, equals(expectedIsWrite));
|
| + };
|
| + libraryElement.unit.accept(visitor);
|
| + expect(count, equals(1));
|
| + }
|
| +}
|
| +
|
| +typedef void MethodInvocationHandler(MethodInvocation node,
|
| + MethodInvocationSemantics semantics);
|
| +typedef void AccessHandler(Expression node, AccessSemantics semantics);
|
| +
|
| +/**
|
| + * Visitor class used to run the tests.
|
| + */
|
| +class TestVisitor extends RecursiveAstVisitor {
|
| + MethodInvocationHandler onMethodInvocation;
|
| + AccessHandler onAccess;
|
| +
|
| + @override
|
| + visitMethodInvocation(MethodInvocation node) {
|
| + onMethodInvocation(node, classifyMethodInvocation(node));
|
| + }
|
| +
|
| + @override
|
| + visitPrefixedIdentifier(PrefixedIdentifier node) {
|
| + onAccess(node, classifyPrefixedIdentifier(node));
|
| + }
|
| +
|
| + @override
|
| + visitPropertyAccess(PropertyAccess node) {
|
| + onAccess(node, classifyPropertyAccess(node));
|
| + }
|
| +
|
| + @override
|
| + visitSimpleIdentifier(SimpleIdentifier node) {
|
| + AccessSemantics semantics = classifyBareIdentifier(node);
|
| + if (semantics != null) {
|
| + onAccess(node, semantics);
|
| + }
|
| + }
|
| +}
|
|
|