blob: 5e41ef607417a0352e99f2fdd8e08f950bbef8b4 [file] [log] [blame]
// 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.
library engine.incremental_resolver_test;
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/incremental_logger.dart' as log;
import 'package:analyzer/src/generated/incremental_resolution_validator.dart';
import 'package:analyzer/src/generated/incremental_resolver.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/generated/testing/ast_factory.dart';
import 'package:analyzer/src/generated/testing/element_factory.dart';
import 'package:unittest/unittest.dart';
import '../reflective_tests.dart';
import 'parser_test.dart';
import 'resolver_test.dart';
import 'test_support.dart';
main() {
groupSep = ' | ';
runReflectiveTests(DeclarationMatcherTest);
runReflectiveTests(IncrementalResolverTest);
runReflectiveTests(PoorMansIncrementalResolutionTest);
runReflectiveTests(ResolutionContextBuilderTest);
}
void _assertEqualError(AnalysisError incrError, AnalysisError fullError) {
expect(incrError.errorCode, same(fullError.errorCode));
expect(incrError.source, fullError.source);
expect(incrError.offset, fullError.offset);
expect(incrError.length, fullError.length);
expect(incrError.message, fullError.message);
}
void _assertEqualErrors(List<AnalysisError> incrErrors,
List<AnalysisError> fullErrors) {
expect(incrErrors, hasLength(fullErrors.length));
if (incrErrors.isNotEmpty) {
incrErrors.sort((a, b) => a.offset - b.offset);
}
if (fullErrors.isNotEmpty) {
fullErrors.sort((a, b) => a.offset - b.offset);
}
int length = incrErrors.length;
for (int i = 0; i < length; i++) {
AnalysisError incrError = incrErrors[i];
AnalysisError fullError = fullErrors[i];
_assertEqualError(incrError, fullError);
}
}
@reflectiveTest
class DeclarationMatcherTest extends ResolverTestCase {
void setUp() {
super.setUp();
test_resolveApiChanges = true;
}
void test_false_class_annotation_accessor_edit() {
_assertDoesNotMatch(r'''
const my_annotationA = const Object();
const my_annotationB = const Object();
@my_annotationA
class A {
}
''', r'''
const my_annotationA = const Object();
const my_annotationB = const Object();
@my_annotationB
class A {
}
''');
}
void test_false_class_annotation_constructor_edit() {
_assertDoesNotMatch(r'''
class MyAnnotationA {
const MyAnnotationA();
}
class MyAnnotationB {
const MyAnnotationB();
}
@MyAnnotationA()
class A {
}
''', r'''
class MyAnnotationA {
const MyAnnotationA();
}
class MyAnnotationB {
const MyAnnotationB();
}
@MyAnnotationB()
class A {
}
''');
}
void test_false_class_annotations_add() {
_assertDoesNotMatch(r'''
const my_annotation = const Object();
class A {
}
''', r'''
const my_annotation = const Object();
@my_annotation
class A {
}
''');
}
void test_false_class_annotations_remove() {
_assertDoesNotMatch(r'''
const my_annotation = const Object();
@my_annotation
class A {
}
''', r'''
const my_annotation = const Object();
class A {
}
''');
}
void test_false_class_list_add() {
_assertDoesNotMatch(r'''
class A {}
class B {}
''', r'''
class A {}
class B {}
class C {}
''');
}
void test_false_class_list_remove() {
_assertDoesNotMatch(r'''
class A {}
class B {}
class C {}
''', r'''
class A {}
class B {}
''');
}
void test_false_class_typeParameters_bounds_add() {
_assertDoesNotMatch(r'''
class A {}
class B<T> {
T f;
}
''', r'''
class A {}
class B<T extends A> {
T f;
}
''');
}
void test_false_class_typeParameters_bounds_remove() {
_assertDoesNotMatch(r'''
class A {}
class B<T extends A> {
T f;
}
''', r'''
class A {}
class B<T> {
T f;
}
''');
}
void test_false_classMemberAccessor_list_add() {
_assertDoesNotMatchOK(r'''
class A {
get a => 1;
get b => 2;
}
''', r'''
class A {
get a => 1;
get b => 2;
get c => 3;
}
''');
}
void test_false_classMemberAccessor_list_remove() {
_assertDoesNotMatch(r'''
class A {
get a => 1;
get b => 2;
get c => 3;
}
''', r'''
class A {
get a => 1;
get b => 2;
}
''');
}
void test_false_classMemberAccessor_wasGetter() {
_assertDoesNotMatchOK(r'''
class A {
get a => 1;
}
''', r'''
class A {
set a(x) {}
}
''');
}
void test_false_classMemberAccessor_wasInstance() {
_assertDoesNotMatchOK(r'''
class A {
get a => 1;
}
''', r'''
class A {
static get a => 1;
}
''');
}
void test_false_classMemberAccessor_wasSetter() {
_assertDoesNotMatchOK(r'''
class A {
set a(x) {}
}
''', r'''
class A {
get a => 1;
}
''');
}
void test_false_classMemberAccessor_wasStatic() {
_assertDoesNotMatchOK(r'''
class A {
static get a => 1;
}
''', r'''
class A {
get a => 1;
}
''');
}
void test_false_classTypeAlias_list_add() {
_assertDoesNotMatch(r'''
class M {}
class A = Object with M;
''', r'''
class M {}
class A = Object with M;
class B = Object with M;
''');
}
void test_false_classTypeAlias_list_remove() {
_assertDoesNotMatch(r'''
class M {}
class A = Object with M;
class B = Object with M;
''', r'''
class M {}
class A = Object with M;
''');
}
void test_false_classTypeAlias_typeParameters_bounds_add() {
_assertDoesNotMatch(r'''
class M<T> {}
class A {}
class B<T> = Object with M<T>;
''', r'''
class M<T> {}
class A {}
class B<T extends A> = Object with M<T>;
''');
}
void test_false_classTypeAlias_typeParameters_bounds_remove() {
_assertDoesNotMatch(r'''
class M<T> {}
class A {}
class B<T extends A> = Object with M<T>;
''', r'''
class M<T> {}
class A {}
class B<T> = Object with M<T>;
''');
}
void test_false_constructor_parameters_list_add() {
_assertDoesNotMatch(r'''
class A {
A();
}
''', r'''
class A {
A(int p);
}
''');
}
void test_false_constructor_parameters_list_remove() {
_assertDoesNotMatch(r'''
class A {
A(int p);
}
''', r'''
class A {
A();
}
''');
}
void test_false_constructor_parameters_type_edit() {
_assertDoesNotMatch(r'''
class A {
A(int p);
}
''', r'''
class A {
A(String p);
}
''');
}
void test_false_constructor_unnamed_add_hadParameters() {
_assertDoesNotMatch(r'''
class A {
}
''', r'''
class A {
A(int p) {}
}
''');
}
void test_false_constructor_unnamed_remove_hadParameters() {
_assertDoesNotMatch(r'''
class A {
A(int p) {}
}
''', r'''
class A {
}
''');
}
void test_false_defaultFieldFormalParameterElement_wasSimple() {
_assertDoesNotMatch(r'''
class A {
int field;
A(int field);
}
''', r'''
class A {
int field;
A([this.field = 0]);
}
''');
}
void test_false_enum_constants_add() {
_assertDoesNotMatch(r'''
enum E {A, B}
''', r'''
enum E {A, B, C}
''');
}
void test_false_enum_constants_remove() {
_assertDoesNotMatch(r'''
enum E {A, B, C}
''', r'''
enum E {A, B}
''');
}
void test_false_export_hide_add() {
_assertDoesNotMatch(r'''
export 'dart:async' hide Future;
''', r'''
export 'dart:async' hide Future, Stream;
''');
}
void test_false_export_hide_remove() {
_assertDoesNotMatch(r'''
export 'dart:async' hide Future, Stream;
''', r'''
export 'dart:async' hide Future;
''');
}
void test_false_export_list_add() {
_assertDoesNotMatch(r'''
export 'dart:async';
''', r'''
export 'dart:async';
export 'dart:math';
''');
}
void test_false_export_list_remove() {
_assertDoesNotMatch(r'''
export 'dart:async';
export 'dart:math';
''', r'''
export 'dart:async';
''');
}
void test_false_export_show_add() {
_assertDoesNotMatch(r'''
export 'dart:async' show Future;
''', r'''
export 'dart:async' show Future, Stream;
''');
}
void test_false_export_show_remove() {
_assertDoesNotMatch(r'''
export 'dart:async' show Future, Stream;
''', r'''
export 'dart:async' show Future;
''');
}
void test_false_extendsClause_add() {
_assertDoesNotMatch(r'''
class A {}
class B {}
''', r'''
class A {}
class B extends A {}
''');
}
void test_false_extendsClause_different() {
_assertDoesNotMatch(r'''
class A {}
class B {}
class C extends A {}
''', r'''
class A {}
class B {}
class C extends B {}
''');
}
void test_false_extendsClause_remove() {
_assertDoesNotMatch(r'''
class A {}
class B extends A{}
''', r'''
class A {}
class B {}
''');
}
void test_false_field_list_add() {
_assertDoesNotMatch(r'''
class T {
int A = 1;
int C = 3;
}
''', r'''
class T {
int A = 1;
int B = 2;
int C = 3;
}
''');
}
void test_false_field_list_remove() {
_assertDoesNotMatch(r'''
class T {
int A = 1;
int B = 2;
int C = 3;
}
''', r'''
class T {
int A = 1;
int C = 3;
}
''');
}
void test_false_field_modifier_isConst() {
_assertDoesNotMatch(r'''
class T {
static final A = 1;
}
''', r'''
class T {
static const A = 1;
}
''');
}
void test_false_field_modifier_isFinal() {
_assertDoesNotMatch(r'''
class T {
int A = 1;
}
''', r'''
class T {
final int A = 1;
}
''');
}
void test_false_field_modifier_isStatic() {
_assertDoesNotMatch(r'''
class T {
int A = 1;
}
''', r'''
class T {
static int A = 1;
}
''');
}
void test_false_field_modifier_wasConst() {
_assertDoesNotMatch(r'''
class T {
static const A = 1;
}
''', r'''
class T {
static final A = 1;
}
''');
}
void test_false_field_modifier_wasFinal() {
_assertDoesNotMatch(r'''
class T {
final int A = 1;
}
''', r'''
class T {
int A = 1;
}
''');
}
void test_false_field_modifier_wasStatic() {
_assertDoesNotMatch(r'''
class T {
static int A = 1;
}
''', r'''
class T {
int A = 1;
}
''');
}
void test_false_field_type_differentArgs() {
_assertDoesNotMatch(r'''
class T {
List<int> A;
}
''', r'''
class T {
List<String> A;
}
''');
}
void test_false_fieldFormalParameterElement_wasSimple() {
_assertDoesNotMatch(r'''
class A {
int field;
A(int field);
}
''', r'''
class A {
int field;
A(this.field);
}
''');
}
void test_false_final_type_different() {
_assertDoesNotMatch(r'''
class T {
int A;
}
''', r'''
class T {
String A;
}
''');
}
void test_false_function_async_add() {
_assertDoesNotMatch(r'''
main() {}
''', r'''
main() async {}
''');
}
void test_false_function_async_remove() {
_assertDoesNotMatch(r'''
main() async {}
''', r'''
main() {}
''');
}
void test_false_function_generator_add() {
_assertDoesNotMatch(r'''
main() async {}
''', r'''
main() async* {}
''');
}
void test_false_function_generator_remove() {
_assertDoesNotMatch(r'''
main() async* {}
''', r'''
main() async {}
''');
}
void test_false_functionTypeAlias_list_add() {
_assertDoesNotMatch(r'''
typedef A(int pa);
typedef B(String pb);
''', r'''
typedef A(int pa);
typedef B(String pb);
typedef C(pc);
''');
}
void test_false_functionTypeAlias_list_remove() {
_assertDoesNotMatch(r'''
typedef A(int pa);
typedef B(String pb);
typedef C(pc);
''', r'''
typedef A(int pa);
typedef B(String pb);
''');
}
void test_false_functionTypeAlias_parameters_list_add() {
_assertDoesNotMatch(r'''
typedef A(a);
''', r'''
typedef A(a, b);
''');
}
void test_false_functionTypeAlias_parameters_list_remove() {
_assertDoesNotMatch(r'''
typedef A(a, b);
''', r'''
typedef A(a);
''');
}
void test_false_functionTypeAlias_parameters_type_edit() {
_assertDoesNotMatch(r'''
typedef A(int p);
''', r'''
typedef A(String p);
''');
}
void test_false_functionTypeAlias_returnType_edit() {
_assertDoesNotMatch(r'''
typedef int A();
''', r'''
typedef String A();
''');
}
void test_false_functionTypeAlias_typeParameters_bounds_add() {
_assertDoesNotMatch(r'''
class A {}
typedef F<T>();
''', r'''
class A {}
typedef F<T extends A>();
''');
}
void test_false_functionTypeAlias_typeParameters_bounds_edit() {
_assertDoesNotMatch(r'''
class A {}
class B {}
typedef F<T extends A>();
''', r'''
class A {}
typedef F<T extends B>();
''');
}
void test_false_functionTypeAlias_typeParameters_bounds_remove() {
_assertDoesNotMatch(r'''
class A {}
typedef F<T extends A>();
''', r'''
class A {}
typedef F<T>();
''');
}
void test_false_functionTypeAlias_typeParameters_list_add() {
_assertDoesNotMatch(r'''
typedef F<A>();
''', r'''
typedef F<A, B>();
''');
}
void test_false_functionTypeAlias_typeParameters_list_remove() {
_assertDoesNotMatch(r'''
typedef F<A, B>();
''', r'''
typedef F<A>();
''');
}
void test_false_FunctionTypedFormalParameter_parameters_list_add() {
_assertDoesNotMatch(r'''
main(int callback(int a)) {
}
''', r'''
main(int callback(int a, String b)) {
}
''');
}
void test_false_FunctionTypedFormalParameter_parameters_list_remove() {
_assertDoesNotMatch(r'''
main(int callback(int a, String b)) {
}
''', r'''
main(int callback(int a)) {
}
''');
}
void test_false_FunctionTypedFormalParameter_parameterType() {
_assertDoesNotMatch(r'''
main(int callback(int p)) {
}
''', r'''
main(int callback(String p)) {
}
''');
}
void test_false_FunctionTypedFormalParameter_returnType() {
_assertDoesNotMatch(r'''
main(int callback()) {
}
''', r'''
main(String callback()) {
}
''');
}
void test_false_FunctionTypedFormalParameter_wasSimple() {
_assertDoesNotMatch(r'''
main(int callback) {
}
''', r'''
main(int callback(int a, String b)) {
}
''');
}
void test_false_implementsClause_add() {
_assertDoesNotMatch(r'''
class A {}
class B {}
''', r'''
class A {}
class B implements A {}
''');
}
void test_false_implementsClause_remove() {
_assertDoesNotMatch(r'''
class A {}
class B implements A {}
''', r'''
class A {}
class B {}
''');
}
void test_false_implementsClause_reorder() {
_assertDoesNotMatch(r'''
class A {}
class B {}
class C implements A, B {}
''', r'''
class A {}
class B {}
class C implements B, A {}
''');
}
void test_false_import_hide_add() {
_assertDoesNotMatch(r'''
import 'dart:async' hide Future;
''', r'''
import 'dart:async' hide Future, Stream;
''');
}
void test_false_import_hide_remove() {
_assertDoesNotMatch(r'''
import 'dart:async' hide Future, Stream;
''', r'''
import 'dart:async' hide Future;
''');
}
void test_false_import_list_add() {
_assertDoesNotMatch(r'''
import 'dart:async';
''', r'''
import 'dart:async';
import 'dart:math';
''');
}
void test_false_import_list_remove() {
_assertDoesNotMatch(r'''
import 'dart:async';
import 'dart:math';
''', r'''
import 'dart:async';
''');
}
void test_false_import_prefix_add() {
_assertDoesNotMatch(r'''
import 'dart:async';
''', r'''
import 'dart:async' as async;
''');
}
void test_false_import_prefix_edit() {
_assertDoesNotMatch(r'''
import 'dart:async' as oldPrefix;
''', r'''
import 'dart:async' as newPrefix;
''');
}
void test_false_import_prefix_remove() {
_assertDoesNotMatch(r'''
import 'dart:async' as async;
''', r'''
import 'dart:async';
''');
}
void test_false_import_show_add() {
_assertDoesNotMatch(r'''
import 'dart:async' show Future;
''', r'''
import 'dart:async' show Future, Stream;
''');
}
void test_false_import_show_remove() {
_assertDoesNotMatch(r'''
import 'dart:async' show Future, Stream;
''', r'''
import 'dart:async' show Future;
''');
}
void test_false_method_annotation_edit() {
_assertDoesNotMatchOK(r'''
const my_annotationA = const Object();
const my_annotationB = const Object();
class A {
@my_annotationA
void m() {}
}
''', r'''
const my_annotationA = const Object();
const my_annotationB = const Object();
class A {
@my_annotationB
void m() {}
}
''');
}
void test_false_method_annotations_add() {
_assertDoesNotMatchOK(r'''
const my_annotation = const Object();
class A {
void m() {}
}
''', r'''
const my_annotation = const Object();
class A {
@my_annotation
void m() {}
}
''');
}
void test_false_method_annotations_remove() {
_assertDoesNotMatchOK(r'''
const my_annotation = const Object();
class A {
@my_annotation
void m() {}
}
''', r'''
const my_annotation = const Object();
class A {
void m() {}
}
''');
}
void test_false_method_async_add() {
_assertDoesNotMatchOK(r'''
class A {
m() {}
}
''', r'''
class A {
m() async {}
}
''');
}
void test_false_method_async_remove() {
_assertDoesNotMatchOK(r'''
class A {
m() async {}
}
''', r'''
class A {
m() {}
}
''');
}
void test_false_method_generator_add() {
_assertDoesNotMatchOK(r'''
class A {
m() async {}
}
''', r'''
class A {
m() async* {}
}
''');
}
void test_false_method_generator_remove() {
_assertDoesNotMatchOK(r'''
class A {
m() async* {}
}
''', r'''
class A {
m() async {}
}
''');
}
void test_false_method_list_add() {
_assertDoesNotMatchOK(r'''
class A {
a() {}
b() {}
}
''', r'''
class A {
a() {}
b() {}
c() {}
}
''');
}
void test_false_method_list_remove() {
_assertDoesNotMatch(r'''
class A {
a() {}
b() {}
c() {}
}
''', r'''
class A {
a() {}
b() {}
}
''');
}
void test_false_method_parameters_type_edit() {
_assertDoesNotMatchOK(r'''
class A {
m(int p) {
}
}
''', r'''
class A {
m(String p) {
}
}
''');
}
void test_false_method_returnType_edit() {
_assertDoesNotMatchOK(r'''
class A {
int m() {}
}
''', r'''
class A {
String m() {}
}
''');
}
void test_false_part_list_add() {
addNamedSource('/unitA.dart', 'part of lib; class A {}');
addNamedSource('/unitB.dart', 'part of lib; class B {}');
_assertDoesNotMatch(r'''
library lib;
part 'unitA.dart';
''', r'''
library lib;
part 'unitA.dart';
part 'unitB.dart';
''');
}
void test_false_part_list_remove() {
addNamedSource('/unitA.dart', 'part of lib; class A {}');
addNamedSource('/unitB.dart', 'part of lib; class B {}');
_assertDoesNotMatch(r'''
library lib;
part 'unitA.dart';
part 'unitB.dart';
''', r'''
library lib;
part 'unitA.dart';
''');
}
void test_false_SimpleFormalParameter_named_differentName() {
_assertDoesNotMatch(r'''
main({int oldName}) {
}
''', r'''
main({int newName}) {
}
''');
}
void test_false_SimpleFormalParameter_namedDefault_addValue() {
_assertDoesNotMatch(r'''
main({int p}) {
}
''', r'''
main({int p: 2}) {
}
''');
}
void test_false_SimpleFormalParameter_namedDefault_differentValue() {
_assertDoesNotMatch(r'''
main({int p: 1}) {
}
''', r'''
main({int p: 2}) {
}
''');
}
void test_false_SimpleFormalParameter_namedDefault_removeValue() {
_assertDoesNotMatch(r'''
main({int p: 1}) {
}
''', r'''
main({int p}) {
}
''');
}
void test_false_SimpleFormalParameter_optionalDefault_addValue() {
_assertDoesNotMatch(r'''
main([int p]) {
}
''', r'''
main([int p = 2]) {
}
''');
}
void test_false_SimpleFormalParameter_optionalDefault_differentValue() {
_assertDoesNotMatch(r'''
main([int p = 1]) {
}
''', r'''
main([int p = 2]) {
}
''');
}
void test_false_SimpleFormalParameter_optionalDefault_removeValue() {
_assertDoesNotMatch(r'''
main([int p = 1]) {
}
''', r'''
main([int p]) {
}
''');
}
void test_false_topLevelAccessor_list_add() {
_assertDoesNotMatch(r'''
get a => 1;
get b => 2;
''', r'''
get a => 1;
get b => 2;
get c => 3;
''');
}
void test_false_topLevelAccessor_list_remove() {
_assertDoesNotMatch(r'''
get a => 1;
get b => 2;
get c => 3;
''', r'''
get a => 1;
get b => 2;
''');
}
void test_false_topLevelAccessor_wasGetter() {
_assertDoesNotMatch(r'''
get a => 1;
''', r'''
set a(x) {}
''');
}
void test_false_topLevelAccessor_wasSetter() {
_assertDoesNotMatch(r'''
set a(x) {}
''', r'''
get a => 1;
''');
}
void test_false_topLevelFunction_list_add() {
_assertDoesNotMatch(r'''
a() {}
b() {}
''', r'''
a() {}
b() {}
c() {}
''');
}
void test_false_topLevelFunction_list_remove() {
_assertDoesNotMatch(r'''
a() {}
b() {}
c() {}
''', r'''
a() {}
b() {}
''');
}
void test_false_topLevelFunction_parameters_list_add() {
_assertDoesNotMatch(r'''
main(int a, int b) {
}
''', r'''
main(int a, int b, int c) {
}
''');
}
void test_false_topLevelFunction_parameters_list_remove() {
_assertDoesNotMatch(r'''
main(int a, int b, int c) {
}
''', r'''
main(int a, int b) {
}
''');
}
void test_false_topLevelFunction_parameters_type_edit() {
_assertDoesNotMatch(r'''
main(int a, int b, int c) {
}
''', r'''
main(int a, String b, int c) {
}
''');
}
void test_false_topLevelFunction_returnType_edit() {
_assertDoesNotMatch(r'''
int a() {}
''', r'''
String a() {}
''');
}
void test_false_topLevelVariable_list_add() {
_assertDoesNotMatch(r'''
const int A = 1;
const int C = 3;
''', r'''
const int A = 1;
const int B = 2;
const int C = 3;
''');
}
void test_false_topLevelVariable_list_remove() {
_assertDoesNotMatch(r'''
const int A = 1;
const int B = 2;
const int C = 3;
''', r'''
const int A = 1;
const int C = 3;
''');
}
void test_false_topLevelVariable_modifier_isConst() {
_assertDoesNotMatch(r'''
final int A = 1;
''', r'''
const int A = 1;
''');
}
void test_false_topLevelVariable_modifier_isFinal() {
_assertDoesNotMatch(r'''
int A = 1;
''', r'''
final int A = 1;
''');
}
void test_false_topLevelVariable_modifier_wasConst() {
_assertDoesNotMatch(r'''
const int A = 1;
''', r'''
final int A = 1;
''');
}
void test_false_topLevelVariable_modifier_wasFinal() {
_assertDoesNotMatch(r'''
final int A = 1;
''', r'''
int A = 1;
''');
}
void test_false_topLevelVariable_synthetic_wasGetter() {
_assertDoesNotMatch(r'''
int get A => 1;
''', r'''
final int A = 1;
''');
}
void test_false_topLevelVariable_type_different() {
_assertDoesNotMatch(r'''
int A;
''', r'''
String A;
''');
}
void test_false_topLevelVariable_type_differentArgs() {
_assertDoesNotMatch(r'''
List<int> A;
''', r'''
List<String> A;
''');
}
void test_false_type_noTypeArguments_hadTypeArguments() {
_assertDoesNotMatch(r'''
class A<T> {}
A<int> main() {
}
''', r'''
class A<T> {}
A main() {
}
''');
}
void test_false_withClause_add() {
_assertDoesNotMatch(r'''
class A {}
class B {}
''', r'''
class A {}
class B extends Object with A {}
''');
}
void test_false_withClause_remove() {
_assertDoesNotMatch(r'''
class A {}
class B extends Object with A {}
''', r'''
class A {}
class B {}
''');
}
void test_false_withClause_reorder() {
_assertDoesNotMatch(r'''
class A {}
class B {}
class C extends Object with A, B {}
''', r'''
class A {}
class B {}
class C extends Object with B, A {}
''');
}
void test_true_class_annotations_same() {
_assertMatches(r'''
const my_annotation = const Object();
@my_annotation
class A {
}
''', r'''
const my_annotation = const Object();
@my_annotation
class A {
}
''');
}
void test_true_class_list_reorder() {
_assertMatches(r'''
class A {}
class B {}
class C {}
''', r'''
class C {}
class A {}
class B {}
''');
}
void test_true_class_list_same() {
_assertMatches(r'''
class A {}
class B {}
class C {}
''', r'''
class A {}
class B {}
class C {}
''');
}
void test_true_class_typeParameters_same() {
_assertMatches(r'''
class A<T> {}
''', r'''
class A<T> {}
''');
}
void test_true_classMemberAccessor_getterSetter() {
_assertMatches(r'''
class A {
int _test;
get test => _test;
set test(v) {
_test = v;
}
}
''', r'''
class A {
int _test;
get test => _test;
set test(v) {
_test = v;
}
}
''');
}
void test_true_classMemberAccessor_list_reorder() {
_assertMatches(r'''
class A {
get a => 1;
get b => 2;
get c => 3;
}
''', r'''
class A {
get c => 3;
get a => 1;
get b => 2;
}
''');
}
void test_true_classMemberAccessor_list_same() {
_assertMatches(r'''
class A {
get a => 1;
get b => 2;
get c => 3;
}
''', r'''
class A {
get a => 1;
get b => 2;
get c => 3;
}
''');
}
void test_true_classTypeAlias_list_reorder() {
_assertMatches(r'''
class M {}
class A = Object with M;
class B = Object with M;
class C = Object with M;
''', r'''
class M {}
class C = Object with M;
class A = Object with M;
class B = Object with M;
''');
}
void test_true_classTypeAlias_list_same() {
_assertMatches(r'''
class M {}
class A = Object with M;
class B = Object with M;
class C = Object with M;
''', r'''
class M {}
class A = Object with M;
class B = Object with M;
class C = Object with M;
''');
}
void test_true_classTypeAlias_typeParameters_same() {
_assertMatches(r'''
class M<T> {}
class A<T> {}
class B<T> = A<T> with M<T>;
''', r'''
class M<T> {}
class A<T> {}
class B<T> = A<T> with M<T>;
''');
}
void test_true_constructor_named_same() {
_assertMatches(r'''
class A {
A.name(int p);
}
''', r'''
class A {
A.name(int p);
}
''');
}
void test_true_constructor_unnamed_add_noParameters() {
_assertMatches(r'''
class A {
}
''', r'''
class A {
A() {}
}
''');
}
void test_true_constructor_unnamed_remove_noParameters() {
_assertMatches(r'''
class A {
A() {}
}
''', r'''
class A {
}
''');
}
void test_true_constructor_unnamed_same() {
_assertMatches(r'''
class A {
A(int p);
}
''', r'''
class A {
A(int p);
}
''');
}
void test_true_defaultFieldFormalParameterElement() {
_assertMatches(r'''
class A {
int field;
A([this.field = 0]);
}
''', r'''
class A {
int field;
A([this.field = 0]);
}
''');
}
void test_true_enum_constants_reorder() {
_assertMatches(r'''
enum E {A, B, C}
''', r'''
enum E {C, A, B}
''');
}
void test_true_enum_list_reorder() {
_assertMatches(r'''
enum A {A1, A2, A3}
enum B {B1, B2, B3}
enum C {C1, C2, C3}
''', r'''
enum C {C1, C2, C3}
enum A {A1, A2, A3}
enum B {B1, B2, B3}
''');
}
void test_true_enum_list_same() {
_assertMatches(r'''
enum A {A1, A2, A3}
enum B {B1, B2, B3}
enum C {C1, C2, C3}
''', r'''
enum A {A1, A2, A3}
enum B {B1, B2, B3}
enum C {C1, C2, C3}
''');
}
void test_true_executable_same_hasLabel() {
_assertMatches(r'''
main() {
label: return 42;
}
''', r'''
main() {
label: return 42;
}
''');
}
void test_true_executable_same_hasLocalVariable() {
_assertMatches(r'''
main() {
int a = 42;
}
''', r'''
main() {
int a = 42;
}
''');
}
void test_true_export_hide_reorder() {
_assertMatches(r'''
export 'dart:async' hide Future, Stream;
''', r'''
export 'dart:async' hide Stream, Future;
''');
}
void test_true_export_list_reorder() {
_assertMatches(r'''
export 'dart:async';
export 'dart:math';
''', r'''
export 'dart:math';
export 'dart:async';
''');
}
void test_true_export_list_same() {
_assertMatches(r'''
export 'dart:async';
export 'dart:math';
''', r'''
export 'dart:async';
export 'dart:math';
''');
}
void test_true_export_show_reorder() {
_assertMatches(r'''
export 'dart:async' show Future, Stream;
''', r'''
export 'dart:async' show Stream, Future;
''');
}
void test_true_extendsClause_same() {
_assertMatches(r'''
class A {}
class B extends A {}
''', r'''
class A {}
class B extends A {}
''');
}
void test_true_field_list_reorder() {
_assertMatches(r'''
class T {
int A = 1;
int B = 2;
int C = 3;
}
''', r'''
class T {
int C = 3;
int A = 1;
int B = 2;
}
''');
}
void test_true_field_list_same() {
_assertMatches(r'''
class T {
int A = 1;
int B = 2;
int C = 3;
}
''', r'''
class T {
int A = 1;
int B = 2;
int C = 3;
}
''');
}
void test_true_fieldFormalParameter() {
_assertMatches(r'''
class A {
int field;
A(this.field);
}
''', r'''
class A {
int field;
A(this.field);
}
''');
}
void test_true_functionTypeAlias_list_reorder() {
_assertMatches(r'''
typedef A(int pa);
typedef B(String pb);
typedef C(pc);
''', r'''
typedef C(pc);
typedef A(int pa);
typedef B(String pb);
''');
}
void test_true_functionTypeAlias_list_same() {
_assertMatches(r'''
typedef String A(int pa);
typedef int B(String pb);
typedef C(pc);
''', r'''
typedef String A(int pa);
typedef int B(String pb);
typedef C(pc);
''');
}
void test_true_functionTypeAlias_typeParameters_list_same() {
_assertMatches(r'''
typedef F<A, B, C>();
''', r'''
typedef F<A, B, C>();
''');
}
void test_true_FunctionTypedFormalParameter() {
_assertMatches(r'''
main(int callback(int a, String b)) {
}
''', r'''
main(int callback(int a, String b)) {
}
''');
}
void test_true_implementsClause_same() {
_assertMatches(r'''
class A {}
class B implements A {}
''', r'''
class A {}
class B implements A {}
''');
}
void test_true_import_hide_reorder() {
_assertMatches(r'''
import 'dart:async' hide Future, Stream;
''', r'''
import 'dart:async' hide Stream, Future;
''');
}
void test_true_import_list_reorder() {
_assertMatches(r'''
import 'dart:async';
import 'dart:math';
''', r'''
import 'dart:math';
import 'dart:async';
''');
}
void test_true_import_list_same() {
_assertMatches(r'''
import 'dart:async';
import 'dart:math';
''', r'''
import 'dart:async';
import 'dart:math';
''');
}
void test_true_import_prefix() {
_assertMatches(r'''
import 'dart:async' as async;
''', r'''
import 'dart:async' as async;
''');
}
void test_true_import_show_reorder() {
_assertMatches(r'''
import 'dart:async' show Future, Stream;
''', r'''
import 'dart:async' show Stream, Future;
''');
}
void test_true_method_annotation_accessor_same() {
_assertMatches(r'''
const my_annotation = const Object();
class A {
@my_annotation
void m() {}
}
''', r'''
const my_annotation = const Object();
class A {
@my_annotation
void m() {}
}
''');
}
void test_true_method_annotation_constructor_same() {
_assertMatches(r'''
class MyAnnotation {
const MyAnnotation();
}
class A {
@MyAnnotation()
void m() {}
}
''', r'''
class MyAnnotation {
const MyAnnotation();
}
class A {
@MyAnnotation()
void m() {}
}
''');
}
void test_true_method_async() {
_assertMatches(r'''
class A {
m() async {}
}
''', r'''
class A {
m() async {}
}
''');
}
void test_true_method_list_reorder() {
_assertMatches(r'''
class A {
a() {}
b() {}
c() {}
}
''', r'''
class A {
c() {}
a() {}
b() {}
}
''');
}
void test_true_method_list_same() {
_assertMatches(r'''
class A {
a() {}
b() {}
c() {}
}
''', r'''
class A {
a() {}
b() {}
c() {}
}
''');
}
void test_true_method_operator_minus() {
_assertMatches(r'''
class A {
operator -(other) {}
}
''', r'''
class A {
operator -(other) {}
}
''');
}
void test_true_method_operator_minusUnary() {
_assertMatches(r'''
class A {
operator -() {}
}
''', r'''
class A {
operator -() {}
}
''');
}
void test_true_method_operator_plus() {
_assertMatches(r'''
class A {
operator +(other) {}
}
''', r'''
class A {
operator +(other) {}
}
''');
}
void test_true_method_parameters_type_functionType() {
_assertMatches(r'''
typedef F();
class A {
m(F p) {}
}
''', r'''
typedef F();
class A {
m(F p) {}
}
''');
}
void test_true_part_list_reorder() {
addNamedSource('/unitA.dart', 'part of lib; class A {}');
addNamedSource('/unitB.dart', 'part of lib; class B {}');
_assertMatches(r'''
library lib;
part 'unitA.dart';
part 'unitB.dart';
''', r'''
library lib;
part 'unitB.dart';
part 'unitA.dart';
''');
}
void test_true_part_list_same() {
addNamedSource('/unitA.dart', 'part of lib; class A {}');
addNamedSource('/unitB.dart', 'part of lib; class B {}');
_assertMatches(r'''
library lib;
part 'unitA.dart';
part 'unitB.dart';
''', r'''
library lib;
part 'unitA.dart';
part 'unitB.dart';
''');
}
void test_true_SimpleFormalParameter_optional_differentName() {
_assertMatches(r'''
main([int oldName]) {
}
''', r'''
main([int newName]) {
}
''');
}
void test_true_SimpleFormalParameter_optionalDefault_differentName() {
_assertMatches(r'''
main([int oldName = 1]) {
}
''', r'''
main([int newName = 1]) {
}
''');
}
void test_true_SimpleFormalParameter_required_differentName() {
_assertMatches(r'''
main(int oldName) {
}
''', r'''
main(int newName) {
}
''');
}
void test_true_topLevelAccessor_list_reorder() {
_assertMatches(r'''
set a(x) {}
set b(x) {}
set c(x) {}
''', r'''
set c(x) {}
set a(x) {}
set b(x) {}
''');
}
void test_true_topLevelAccessor_list_same() {
_assertMatches(r'''
get a => 1;
get b => 2;
get c => 3;
''', r'''
get a => 1;
get b => 2;
get c => 3;
''');
}
void test_true_topLevelFunction_list_reorder() {
_assertMatches(r'''
a() {}
b() {}
c() {}
''', r'''
c() {}
a() {}
b() {}
''');
}
void test_true_topLevelFunction_list_same() {
_assertMatches(r'''
a() {}
b() {}
c() {}
''', r'''
a() {}
b() {}
c() {}
''');
}
void test_true_topLevelVariable_list_reorder() {
_assertMatches(r'''
const int A = 1;
const int B = 2;
const int C = 3;
''', r'''
const int C = 3;
const int A = 1;
const int B = 2;
''');
}
void test_true_topLevelVariable_list_same() {
_assertMatches(r'''
const int A = 1;
const int B = 2;
const int C = 3;
''', r'''
const int A = 1;
const int B = 2;
const int C = 3;
''');
}
void test_true_topLevelVariable_type_sameArgs() {
_assertMatches(r'''
Map<int, String> A;
''', r'''
Map<int, String> A;
''');
}
void test_true_type_dynamic() {
_assertMatches(r'''
dynamic a() {}
''', r'''
dynamic a() {}
''');
}
void test_true_type_hasImportPrefix() {
_assertMatches(r'''
import 'dart:async' as async;
async.Future F;
''', r'''
import 'dart:async' as async;
async.Future F;
''');
}
void test_true_type_noTypeArguments_implyAllDynamic() {
_assertMatches(r'''
class A<T> {}
A main() {
}
''', r'''
class A<T> {}
A main() {
}
''');
}
void test_true_type_void() {
_assertMatches(r'''
void a() {}
''', r'''
void a() {}
''');
}
void test_true_withClause_same() {
_assertMatches(r'''
class A {}
class B extends Object with A {}
''', r'''
class A {}
class B extends Object with A {}
''');
}
void _assertDoesNotMatch(String oldContent, String newContent) {
_assertMatchKind(DeclarationMatchKind.MISMATCH, oldContent, newContent);
}
void _assertDoesNotMatchOK(String oldContent, String newContent) {
_assertMatchKind(DeclarationMatchKind.MISMATCH_OK, oldContent, newContent);
}
void _assertMatches(String oldContent, String newContent) {
_assertMatchKind(DeclarationMatchKind.MATCH, oldContent, newContent);
}
void _assertMatchKind(DeclarationMatchKind expectMatch, String oldContent,
String newContent) {
Source source = addSource(oldContent);
LibraryElement library = resolve(source);
CompilationUnit oldUnit = resolveCompilationUnit(source, library);
// parse
CompilationUnit newUnit = ParserTestCase.parseCompilationUnit(newContent);
// build elements
{
ElementHolder holder = new ElementHolder();
ElementBuilder builder = new ElementBuilder(holder);
newUnit.accept(builder);
}
// match
DeclarationMatcher matcher = new DeclarationMatcher();
DeclarationMatchKind matchKind = matcher.matches(newUnit, oldUnit.element);
expect(matchKind, same(expectMatch));
}
}
@reflectiveTest
class IncrementalResolverTest extends ResolverTestCase {
Source source;
String code;
LibraryElement library;
CompilationUnit unit;
void setUp() {
super.setUp();
test_resolveApiChanges = true;
log.logger = log.NULL_LOGGER;
}
void test_classMemberAccessor_body() {
_resolveUnit(r'''
class A {
int get test {
return 1 + 2;
}
}''');
_resolve(_editString('+', '*'), _isFunctionBody);
}
void test_constructor_body() {
_resolveUnit(r'''
class A {
int f;
A(int a, int b) {
f = a + b;
}
}''');
_resolve(_editString('+', '*'), _isFunctionBody);
}
void test_constructor_fieldFormalParameter() {
_resolveUnit(r'''
class A {
int xy;
A(this.x);
}''');
_resolve(_editString('this.x', 'this.xy'), _isDeclaration);
}
void test_constructor_fieldInitializer_add() {
_resolveUnit(r'''
class A {
int f;
A(int a, int b);
}''');
_resolve(_editString(');', ') : f = a + b;'), _isClassMember);
}
void test_constructor_fieldInitializer_edit() {
_resolveUnit(r'''
class A {
int f;
A(int a, int b) : f = a + b {
int a = 42;
}
}''');
_resolve(_editString('+', '*'), _isExpression);
}
void test_constructor_label_add() {
_resolveUnit(r'''
class A {
A() {
return 42;
}
}
''');
_resolve(_editString('return', 'label: return'), _isBlock);
}
void test_constructor_localVariable_add() {
_resolveUnit(r'''
class A {
A() {
42;
}
}
''');
_resolve(_editString('42;', 'var res = 42;'), _isBlock);
}
void test_constructor_superConstructorInvocation() {
_resolveUnit(r'''
class A {
A(int p);
}
class B extends A {
B(int a, int b) : super(a + b);
}
''');
_resolve(_editString('+', '*'), _isExpression);
}
void test_function_localFunction_add() {
_resolveUnit(r'''
int main() {
return 0;
}
callIt(f) {}
''');
_resolve(_editString('return 0;', 'callIt((p) {});'), _isBlock);
}
void test_functionBody_body() {
_resolveUnit(r'''
main(int a, int b) {
return a + b;
}''');
_resolve(_editString('+', '*'), _isFunctionBody);
}
void test_functionBody_expression() {
_resolveUnit(r'''
main(int a, int b) => a + b;
''');
_resolve(_editString('+', '*'), _isExpression);
}
void test_functionBody_statement() {
_resolveUnit(r'''
main(int a, int b) {
return a + b;
}''');
_resolve(_editString('+', '*'), _isStatement);
}
void test_method_body() {
_resolveUnit(r'''
class A {
m(int a, int b) {
return a + b;
}
}''');
_resolve(_editString('+', '*'), _isFunctionBody);
}
void test_method_label_add() {
_resolveUnit(r'''
class A {
int m(int a, int b) {
return a + b;
}
}
''');
_resolve(_editString('return', 'label: return'), _isBlock);
}
void test_method_localFunction_add() {
_resolveUnit(r'''
class A {
int m() {
return 0;
}
}
callIt(f) {}
''');
_resolve(_editString('return 0;', 'callIt((p) {});'), _isBlock);
}
void test_method_localVariable_add() {
_resolveUnit(r'''
class A {
int m(int a, int b) {
return a + b;
}
}
''');
_resolve(_editString(' return a + b;', r'''
int res = a + b;
return res;
'''), _isBlock);
}
void test_method_parameter_rename() {
_resolveUnit(r'''
class A {
int m(int a, int b, int c) {
return a + b + c;
}
}
''');
_resolve(_editString(r'''(int a, int b, int c) {
return a + b + c;''', r'''(int a, int second, int c) {
return a + second + c;'''), _isDeclaration);
}
void test_superInvocation() {
_resolveUnit(r'''
class A {
foo(p) {}
}
class B extends A {
bar() {
super.foo(1 + 2);
}
}''');
_resolve(_editString('+', '*'), _isFunctionBody);
}
void test_topLevelAccessor_body() {
_resolveUnit(r'''
int get test {
return 1 + 2;
}''');
_resolve(_editString('+', '*'), _isFunctionBody);
}
void test_topLevelFunction_label_add() {
_resolveUnit(r'''
int main(int a, int b) {
return a + b;
}
''');
_resolve(_editString(' return', 'label: return a + b;'), _isBlock);
}
void test_topLevelFunction_label_remove() {
_resolveUnit(r'''
int main(int a, int b) {
label: return a + b;
}
''');
_resolve(_editString('label: ', ''), _isBlock);
}
void test_topLevelFunction_localVariable_add() {
_resolveUnit(r'''
int main(int a, int b) {
return a + b;
}
''');
_resolve(_editString(' return a + b;', r'''
int res = a + b;
return res;
'''), _isBlock);
}
void test_topLevelFunction_localVariable_remove() {
_resolveUnit(r'''
int main(int a, int b) {
int res = a * b;
return a + b;
}
''');
_resolve(_editString('int res = a * b;', ''), _isBlock);
}
void test_topLevelFunction_parameter_inFunctionTyped_rename() {
_resolveUnit(r'''
test(f(int a, int b)) {
}
''');
_resolve(_editString('test(f(int a', 'test(f2(int a2'), _isDeclaration);
}
void test_topLevelFunction_parameter_rename() {
_resolveUnit(r'''
int main(int a, int b) {
return a + b;
}
''');
_resolve(_editString(r'''(int a, int b) {
return a + b;''', r'''(int first, int b) {
return first + b;'''), _isDeclaration);
}
void test_topLevelVariable_initializer() {
_resolveUnit(r'''
int C = 1 + 2;
''');
_resolve(_editString('+', '*'), _isExpression);
}
void test_updateElementOffset() {
_resolveUnit(r'''
class A {
int am(String ap) {
int av = 1;
return av;
}
}
main(int a, int b) {
return a + b;
}
class B {
int bm(String bp) {
int bv = 1;
return bv;
}
}
''');
_resolve(_editString('+', ' + '), _isStatement);
}
_Edit _editString(String search, String replacement, [int length]) {
int offset = code.indexOf(search);
expect(offset, isNot(-1));
if (length == null) {
length = search.length;
}
return new _Edit(offset, length, replacement);
}
/**
* Applies [edit] to [code], find the [AstNode] specified by [predicate]
* and incrementally resolves it.
*
* Then resolves the new code from scratch and validates that results of
* the incremental resolution and non-incremental resolutions are the same.
*/
void _resolve(_Edit edit, Predicate<AstNode> predicate) {
int offset = edit.offset;
// parse "newCode"
String newCode =
code.substring(0, offset) +
edit.replacement +
code.substring(offset + edit.length);
CompilationUnit newUnit = _parseUnit(newCode);
// replace the node
AstNode oldNode = _findNodeAt(unit, offset, predicate);
AstNode newNode = _findNodeAt(newUnit, offset, predicate);
{
bool success = NodeReplacer.replace(oldNode, newNode);
expect(success, isTrue);
}
// update tokens
{
int delta = edit.replacement.length - edit.length;
_shiftTokens(unit.beginToken, offset, delta);
}
// do incremental resolution
int updateOffset = edit.offset;
int updateEndOld = updateOffset + edit.length;
int updateOldNew = updateOffset + edit.replacement.length;
IncrementalResolver resolver = new IncrementalResolver(
unit.element,
updateOffset,
updateEndOld,
updateOldNew);
bool success = resolver.resolve(newNode);
expect(success, isTrue);
List<AnalysisError> newErrors = analysisContext.computeErrors(source);
// resolve "newCode" from scratch
CompilationUnit fullNewUnit;
{
source = addSource(newCode);
_runTasks();
LibraryElement library = resolve(source);
fullNewUnit = resolveCompilationUnit(source, library);
}
try {
assertSameResolution(unit, fullNewUnit);
} on IncrementalResolutionMismatch catch (mismatch) {
fail(mismatch.message);
}
// errors
List<AnalysisError> newFullErrors =
analysisContext.getErrors(source).errors;
_assertEqualErrors(newErrors, newFullErrors);
// prepare for the next cycle
code = newCode;
}
void _resolveUnit(String code) {
this.code = code;
source = addSource(code);
library = resolve(source);
unit = resolveCompilationUnit(source, library);
_runTasks();
}
void _runTasks() {
AnalysisResult result = analysisContext.performAnalysisTask();
while (result.changeNotices != null) {
result = analysisContext.performAnalysisTask();
}
}
static AstNode _findNodeAt(CompilationUnit oldUnit, int offset,
Predicate<AstNode> predicate) {
NodeLocator locator = new NodeLocator.con1(offset);
AstNode node = locator.searchWithin(oldUnit);
return node.getAncestor(predicate);
}
static bool _isBlock(AstNode node) => node is Block;
static bool _isClassMember(AstNode node) => node is ClassMember;
static bool _isDeclaration(AstNode node) => node is Declaration;
static bool _isExpression(AstNode node) => node is Expression;
static bool _isFunctionBody(AstNode node) => node is FunctionBody;
static bool _isStatement(AstNode node) => node is Statement;
static CompilationUnit _parseUnit(String code) {
var errorListener = new BooleanErrorListener();
var reader = new CharSequenceReader(code);
var scanner = new Scanner(null, reader, errorListener);
var token = scanner.tokenize();
var parser = new Parser(null, errorListener);
return parser.parseCompilationUnit(token);
}
static void _shiftTokens(Token token, int afterOffset, int delta) {
while (token.type != TokenType.EOF) {
if (token.offset >= afterOffset) {
token.applyDelta(delta);
}
token = token.next;
}
}
}
/**
* The test for [poorMansIncrementalResolution] function and its integration
* into [AnalysisContext].
*/
@reflectiveTest
class PoorMansIncrementalResolutionTest extends ResolverTestCase {
Source source;
String code;
LibraryElement oldLibrary;
CompilationUnit oldUnit;
CompilationUnitElement oldUnitElement;
void fail_updateErrors_removeExisting_duplicateMethodDeclaration() {
// TODO(scheglov) We fail to remove the second "foo" declaration.
// So, we still have the same duplicate declaration problem.
_resolveUnit(r'''
class A {
void foo() {}
void foo() {}
}
''');
_updateAndValidate(r'''
class A {
void foo() {}
void foo2() {}
}
''');
}
void setUp() {
super.setUp();
_resetWithIncremental(true);
}
void test_dartDoc_beforeField() {
_resolveUnit(r'''
class A {
/**
* A field [field] of type [int] in class [A].
*/
int field;
}
''');
_updateAndValidate(r'''
class A {
/**
* A field [field] of the type [int] in the class [A].
* Updated, with a reference to the [String] type.
*/
int field;
}
''');
}
void test_dartDoc_clumsy_addReference() {
_resolveUnit(r'''
/**
* aaa bbbb
*/
main() {
}
''');
_updateAndValidate(r'''
/**
* aaa [main] bbbb
*/
main() {
}
''');
}
void test_dartDoc_clumsy_removeReference() {
_resolveUnit(r'''
/**
* aaa [main] bbbb
*/
main() {
}
''');
_updateAndValidate(r'''
/**
* aaa bbbb
*/
main() {
}
''');
}
void test_dartDoc_clumsy_updateText_beforeKeywordToken() {
_resolveUnit(r'''
/**
* A comment with the [int] type reference.
*/
class A {}
''');
_updateAndValidate(r'''
/**
* A comment with the [int] type reference.
* Plus reference to [A] itself.
*/
class A {}
''');
}
void test_dartDoc_clumsy_updateText_insert() {
_resolveUnit(r'''
/**
* A function [main] with a parameter [p] of type [int].
*/
main(int p) {
unresolvedFunctionProblem();
}
/**
* Other comment with [int] reference.
*/
foo() {}
''');
_updateAndValidate(r'''
/**
* A function [main] with a parameter [p] of type [int].
* Inserted text with [String] reference.
*/
main(int p) {
unresolvedFunctionProblem();
}
/**
* Other comment with [int] reference.
*/
foo() {}
''');
}
void test_dartDoc_clumsy_updateText_remove() {
_resolveUnit(r'''
/**
* A function [main] with a parameter [p] of type [int].
* Some text with [String] reference to remove.
*/
main(int p) {
}
/**
* Other comment with [int] reference.
*/
foo() {}
''');
_updateAndValidate(r'''
/**
* A function [main] with a parameter [p] of type [int].
*/
main(int p) {
}
/**
* Other comment with [int] reference.
*/
foo() {}
''');
}
void test_dartDoc_elegant_addReference() {
_resolveUnit(r'''
/// aaa bbb
main() {
return 1;
}
''');
_updateAndValidate(r'''
/// aaa [main] bbb
/// ccc [int] ddd
main() {
return 2;
}
''');
}
void test_dartDoc_elegant_removeReference() {
_resolveUnit(r'''
/// aaa [main] bbb
/// ccc [int] ddd
main() {
return 1;
}
''');
_updateAndValidate(r'''
/// aaa bbb
main() {
return 2;
}
''');
}
void test_endOfLineComment_add_beforeKeywordToken() {
_resolveUnit(r'''
main() {
var v = 42;
}
''');
_updateAndValidate(r'''
main() {
// some comment
var v = 42;
}
''');
}
void test_endOfLineComment_add_beforeStringToken() {
_resolveUnit(r'''
main() {
print(0);
}
''');
_updateAndValidate(r'''
main() {
// some comment
print(0);
}
''');
}
void test_endOfLineComment_edit() {
_resolveUnit(r'''
main() {
// some comment
print(0);
}
''');
_updateAndValidate(r'''
main() {
// edited comment text
print(0);
}
''');
}
void test_endOfLineComment_localFunction_inTopLevelVariable() {
_resolveUnit(r'''
typedef int Binary(one, two, three);
int Global = f((a, b, c) {
return 0; // Some comment
});
''');
_updateAndValidate(r'''
typedef int Binary(one, two, three);
int Global = f((a, b, c) {
return 0; // Some comment
});
''');
}
void test_endOfLineComment_remove() {
_resolveUnit(r'''
main() {
// some comment
print(0);
}
''');
_updateAndValidate(r'''
main() {
print(0);
}
''');
}
void test_false_topLevelFunction_name() {
_resolveUnit(r'''
a() {}
b() {}
''');
_updateAndValidate(r'''
a() {}
bb() {}
''', expectedSuccess: false);
}
void test_false_unbalancedCurlyBrackets_inNew() {
_resolveUnit(r'''
class A {
aaa() {
if (true) {
1;
}
}
bbb() {
print(0123456789);
}
}''');
_updateAndValidate(r'''
class A {
aaa() {
1;
}
}
bbb() {
print(0123456789);
}
}''', expectedSuccess: false);
}
void test_false_unbalancedCurlyBrackets_inOld() {
_resolveUnit(r'''
class A {
aaa() {
1;
}
}
bbb() {
print(0123456789);
}
}''');
_updateAndValidate(r'''
class A {
aaa() {
if (true) {
1;
}
}
bbb() {
print(0123456789);
}
}''', expectedSuccess: false);
}
void test_fieldClassField_propagatedType() {
_resolveUnit(r'''
class A {
static const A b = const B();
const A();
}
class B extends A {
const B();
}
main() {
print(12);
A.b;
}
''');
_updateAndValidate(r'''
class A {
static const A b = const B();
const A();
}
class B extends A {
const B();
}
main() {
print(123);
A.b;
}
''');
}
void test_inBody_expression() {
_resolveUnit(r'''
class A {
m() {
print(1);
}
}
''');
_updateAndValidate(r'''
class A {
m() {
print(2 + 3);
}
}
''');
}
void test_inBody_insertStatement() {
_resolveUnit(r'''
main() {
print(1);
}
''');
_updateAndValidate(r'''
main() {
print(0);
print(1);
}
''');
}
void test_inBody_tokenToNode() {
_resolveUnit(r'''
main() {
var v = 42;
print(v);
}
''');
_updateAndValidate(r'''
main() {
int v = 42;
print(v);
}
''');
}
void test_multiple_emptyLine() {
_resolveUnit(r'''
class A {
m() {
return true;
}
}''');
for (int i = 0; i < 6; i++) {
if (i.isEven) {
_updateAndValidate(r'''
class A {
m() {
return true;
}
}''', compareWithFull: false);
} else {
_updateAndValidate(r'''
class A {
m() {
return true;
}
}''', compareWithFull: false);
}
}
}
void test_multiple_expression() {
_resolveUnit(r'''
main() {
print(1);
}''');
for (int i = 0; i < 6; i++) {
if (i.isEven) {
_updateAndValidate(r'''
main() {
print(12);
}''', compareWithFull: false);
} else {
_updateAndValidate(r'''
main() {
print(1);
}''', compareWithFull: false);
}
}
}
void test_true_emptyLine_betweenClassMembers_insert() {
_resolveUnit(r'''
class A {
a() {}
b() {}
}
''');
_updateAndValidate(r'''
class A {
a() {}
b() {}
}
''');
}
void test_true_emptyLine_betweenClassMembers_remove() {
_resolveUnit(r'''
class A {
a() {}
b() {}
}
''');
_updateAndValidate(r'''
class A {
a() {}
b() {}
}
''');
}
void test_true_emptyLine_betweenCompilationUnitMembers_insert() {
_resolveUnit(r'''
a() {}
b() {}
''');
_updateAndValidate(r'''
a() {}
b() {}
''');
}
void test_true_emptyLine_betweenCompilationUnitMembers_remove() {
_resolveUnit(r'''
a() {
print(1)
}
b() {
foo(42);
}
foo(String p) {}
''');
_updateAndValidate(r'''
a() {
print(1)
}
b() {
foo(42);
}
foo(String p) {}
''');
}
void test_true_wholeConstructor() {
_resolveUnit(r'''
class A {
A(int a) {
print(a);
}
}
''');
_updateAndValidate(r'''
class A {
A(int b) {
print(b);
}
}
''');
}
void test_true_wholeConstructor_addInitializer() {
_resolveUnit(r'''
class A {
int field;
A();
}
''');
_updateAndValidate(r'''
class A {
int field;
A() : field = 5;
}
''');
}
void test_true_wholeFunction() {
_resolveUnit(r'''
foo() {}
main(int a) {
print(a);
}
''');
_updateAndValidate(r'''
foo() {}
main(int b) {
print(b);
}
''');
}
void test_true_wholeFunction_firstTokenInUnit() {
_resolveUnit(r'''
main(int a) {
print(a);
}
''');
_updateAndValidate(r'''
main(int b) {
print(b);
}
''');
}
void test_true_wholeMethod() {
_resolveUnit(r'''
class A {
main(int a) {
print(a);
}
}
''');
_updateAndValidate(r'''
class A {
main(int b) {
print(b);
}
}
''');
}
void test_unusedHint_add_wasUsedOnlyInPart() {
Source partSource = addNamedSource('/my_unit.dart', r'''
part of lib;
f(A a) {
a._foo();
}
''');
_resolveUnit(r'''
library lib;
part 'my_unit.dart';
class A {
_foo() {
print(1);
}
}
''');
_runTasks();
// perform incremental resolution
_resetWithIncremental(true);
analysisContext2.setContents(partSource, r'''
part of lib;
f(A a) {
// a._foo();
}
''');
// no hints right now, because we delay hints computing
{
List<AnalysisError> errors = analysisContext.getErrors(source).errors;
expect(errors, isEmpty);
}
// a new hint should be added
List<AnalysisError> errors = analysisContext.computeErrors(source);
expect(errors, hasLength(1));
expect(errors[0].errorCode.type, ErrorType.HINT);
// the same hint should be reported using a ChangeNotice
bool noticeFound = false;
AnalysisResult result = analysisContext2.performAnalysisTask();
for (ChangeNotice notice in result.changeNotices) {
if (notice.source == source) {
expect(notice.errors, contains(errors[0]));
noticeFound = true;
}
}
expect(noticeFound, isTrue);
}
void test_unusedHint_false_stillUsedInPart() {
addNamedSource('/my_unit.dart', r'''
part of lib;
f(A a) {
a._foo();
}
''');
_resolveUnit(r'''
library lib;
part 'my_unit.dart';
class A {
_foo() {
print(1);
}
}
''');
// perform incremental resolution
_resetWithIncremental(true);
analysisContext2.setContents(source, r'''
library lib;
part 'my_unit.dart';
class A {
_foo() {
print(12);
}
}
''');
// no hints
List<AnalysisError> errors = analysisContext.getErrors(source).errors;
expect(errors, isEmpty);
}
void test_updateErrors_addNew_hint() {
_resolveUnit(r'''
int main() {
return 42;
}
''');
_updateAndValidate(r'''
int main() {
}
''');
}
void test_updateErrors_addNew_hints() {
_resolveUnit(r'''
main() {
int v = 0;
print(v);
}
''');
_updateAndValidate(r'''
main() {
int v = 0;
}
''');
}
void test_updateErrors_addNew_parse() {
_resolveUnit(r'''
main() {
print(42);
}
''');
_updateAndValidate(r'''
main() {
print(42)
}
''');
}
void test_updateErrors_addNew_resolve() {
_resolveUnit(r'''
main() {
foo();
}
foo() {}
''');
_updateAndValidate(r'''
main() {
bar();
}
foo() {}
''');
}
void test_updateErrors_addNew_resolve2() {
_resolveUnit(r'''
// this comment is important to reproduce the problem
main() {
int vvv = 42;
print(vvv);
}
''');
_updateAndValidate(r'''
// this comment is important to reproduce the problem
main() {
int vvv = 42;
print(vvv2);
}
''');
}
void test_updateErrors_addNew_scan() {
_resolveUnit(r'''
main() {
1;
}
''');
_updateAndValidate(r'''
main() {
1e;
}
''');
}
void test_updateErrors_addNew_verify() {
_resolveUnit(r'''
main() {
foo(0);
}
foo(int p) {}
''');
_updateAndValidate(r'''
main() {
foo('abc');
}
foo(int p) {}
''');
}
void test_updateErrors_removeExisting_hint() {
_resolveUnit(r'''
int main() {
}
''');
_updateAndValidate(r'''
int main() {
return 42;
}
''');
}
void test_updateErrors_removeExisting_verify() {
_resolveUnit(r'''
f1() {
print(1)
}
f2() {
print(22)
}
f3() {
print(333)
}
''');
_updateAndValidate(r'''
f1() {
print(1)
}
f2() {
print(22);
}
f3() {
print(333)
}
''');
}
void test_updateErrors_shiftExisting() {
_resolveUnit(r'''
f1() {
print(1)
}
f2() {
print(2);
}
f3() {
print(333)
}
''');
_updateAndValidate(r'''
f1() {
print(1)
}
f2() {
print(22);
}
f3() {
print(333)
}
''');
}
/**
* Reset the analysis context to have the 'incremental' option set to the
* given value.
*/
void _resetWithIncremental(bool enable) {
AnalysisOptionsImpl analysisOptions = new AnalysisOptionsImpl();
analysisOptions.incremental = enable;
analysisOptions.incrementalApi = enable;
// log.logger = log.PRINT_LOGGER;
log.logger = log.NULL_LOGGER;
analysisContext2.analysisOptions = analysisOptions;
}
void _resolveUnit(String code) {
this.code = code;
source = addSource(code);
oldLibrary = resolve(source);
oldUnit = resolveCompilationUnit(source, oldLibrary);
oldUnitElement = oldUnit.element;
}
void _runTasks() {
AnalysisResult result = analysisContext.performAnalysisTask();
while (result.changeNotices != null) {
result = analysisContext.performAnalysisTask();
}
}
void _updateAndValidate(String newCode, {bool expectedSuccess: true,
bool compareWithFull: true}) {
// Run any pending tasks tasks.
_runTasks();
// Update the source - currently this may cause incremental resolution.
// Then request the updated resolved unit.
_resetWithIncremental(true);
analysisContext2.setContents(source, newCode);
CompilationUnit newUnit = resolveCompilationUnit(source, oldLibrary);
List<AnalysisError> newErrors = analysisContext.computeErrors(source);
// check for expected failure
if (!expectedSuccess) {
expect(newUnit.element, isNot(same(oldUnitElement)));
return;
}
// The existing CompilationUnitElement should be updated.
expect(newUnit.element, same(oldUnitElement));
// The only expected pending task should return the same resolved
// "newUnit", so all clients will get it using the usual way.
AnalysisResult analysisResult = analysisContext.performAnalysisTask();
ChangeNotice notice = analysisResult.changeNotices[0];
expect(notice.resolvedDartUnit, same(newUnit));
// Resolve "newCode" from scratch.
if (compareWithFull) {
_resetWithIncremental(false);
source = addSource(newCode + ' ');
source = addSource(newCode);
_runTasks();
LibraryElement library = resolve(source);
CompilationUnit fullNewUnit = resolveCompilationUnit(source, library);
// Validate tokens.
_assertEqualTokens(newUnit, fullNewUnit);
// Validate that "incremental" and "full" units have the same resolution.
try {
assertSameResolution(newUnit, fullNewUnit, validateTypes: true);
} on IncrementalResolutionMismatch catch (mismatch) {
fail(mismatch.message);
}
List<AnalysisError> newFullErrors =
analysisContext.getErrors(source).errors;
_assertEqualErrors(newErrors, newFullErrors);
// TODO(scheglov) check line info
}
}
static void _assertEqualToken(Token incrToken, Token fullToken) {
// print('[${incrToken.offset}] |$incrToken| vs. [${fullToken.offset}] |$fullToken|');
expect(incrToken.type, fullToken.type);
expect(incrToken.offset, fullToken.offset);
expect(incrToken.length, fullToken.length);
expect(incrToken.lexeme, fullToken.lexeme);
}
static void _assertEqualTokens(CompilationUnit incrUnit,
CompilationUnit fullUnit) {
Token incrToken = incrUnit.beginToken;
Token fullToken = fullUnit.beginToken;
while (incrToken.type != TokenType.EOF && fullToken.type != TokenType.EOF) {
_assertEqualToken(incrToken, fullToken);
// comments
{
Token incrComment = incrToken.precedingComments;
Token fullComment = fullToken.precedingComments;
while (true) {
if (fullComment == null) {
expect(incrComment, isNull);
break;
}
expect(incrComment, isNotNull);
_assertEqualToken(incrComment, fullComment);
incrComment = incrComment.next;
fullComment = fullComment.next;
}
}
// next tokens
incrToken = incrToken.next;
fullToken = fullToken.next;
}
}
}
@reflectiveTest
class ResolutionContextBuilderTest extends EngineTestCase {
GatheringErrorListener listener = new GatheringErrorListener();
void test_scopeFor_ClassDeclaration() {
Scope scope = _scopeFor(_createResolvedClassDeclaration());
EngineTestCase.assertInstanceOf(
(obj) => obj is LibraryScope,
LibraryScope,
scope);
}
void test_scopeFor_ClassTypeAlias() {
Scope scope = _scopeFor(_createResolvedClassTypeAlias());
EngineTestCase.assertInstanceOf(
(obj) => obj is LibraryScope,
LibraryScope,
scope);
}
void test_scopeFor_CompilationUnit() {
Scope scope = _scopeFor(_createResolvedCompilationUnit());
EngineTestCase.assertInstanceOf(
(obj) => obj is LibraryScope,
LibraryScope,
scope);
}
void test_scopeFor_ConstructorDeclaration() {
Scope scope = _scopeFor(_createResolvedConstructorDeclaration());
EngineTestCase.assertInstanceOf(
(obj) => obj is ClassScope,
ClassScope,
scope);
}
void test_scopeFor_ConstructorDeclaration_parameters() {
Scope scope = _scopeFor(_createResolvedConstructorDeclaration().parameters);
EngineTestCase.assertInstanceOf(
(obj) => obj is FunctionScope,
FunctionScope,
scope);
}
void test_scopeFor_FunctionDeclaration() {
Scope scope = _scopeFor(_createResolvedFunctionDeclaration());
EngineTestCase.assertInstanceOf(
(obj) => obj is LibraryScope,
LibraryScope,
scope);
}
void test_scopeFor_FunctionDeclaration_parameters() {
Scope scope =
_scopeFor(_createResolvedFunctionDeclaration().functionExpression.parameters);
EngineTestCase.assertInstanceOf(
(obj) => obj is FunctionScope,
FunctionScope,
scope);
}
void test_scopeFor_FunctionTypeAlias() {
Scope scope = _scopeFor(_createResolvedFunctionTypeAlias());
EngineTestCase.assertInstanceOf(
(obj) => obj is LibraryScope,
LibraryScope,
scope);
}
void test_scopeFor_FunctionTypeAlias_parameters() {
Scope scope = _scopeFor(_createResolvedFunctionTypeAlias().parameters);
EngineTestCase.assertInstanceOf(
(obj) => obj is FunctionTypeScope,
FunctionTypeScope,
scope);
}
void test_scopeFor_MethodDeclaration() {
Scope scope = _scopeFor(_createResolvedMethodDeclaration());
EngineTestCase.assertInstanceOf(
(obj) => obj is ClassScope,
ClassScope,
scope);
}
void test_scopeFor_MethodDeclaration_body() {
Scope scope = _scopeFor(_createResolvedMethodDeclaration().body);
EngineTestCase.assertInstanceOf(
(obj) => obj is FunctionScope,
FunctionScope,
scope);
}
void test_scopeFor_notInCompilationUnit() {
try {
_scopeFor(AstFactory.identifier3("x"));
fail("Expected AnalysisException");
} on AnalysisException catch (exception) {
// Expected
}
}
void test_scopeFor_null() {
try {
_scopeFor(null);
fail("Expected AnalysisException");
} on AnalysisException catch (exception) {
// Expected
}
}
void test_scopeFor_unresolved() {
try {
_scopeFor(AstFactory.compilationUnit());
fail("Expected AnalysisException");
} on AnalysisException catch (exception) {
// Expected
}
}
ClassDeclaration _createResolvedClassDeclaration() {
CompilationUnit unit = _createResolvedCompilationUnit();
String className = "C";
ClassDeclaration classNode = AstFactory.classDeclaration(
null,
className,
AstFactory.typeParameterList(),
null,
null,
null);
unit.declarations.add(classNode);
ClassElement classElement = ElementFactory.classElement2(className);
classNode.name.staticElement = classElement;
(unit.element as CompilationUnitElementImpl).types =
<ClassElement>[classElement];
return classNode;
}
ClassTypeAlias _createResolvedClassTypeAlias() {
CompilationUnit unit = _createResolvedCompilationUnit();
String className = "C";
ClassTypeAlias classNode = AstFactory.classTypeAlias(
className,
AstFactory.typeParameterList(),
null,
null,
null,
null);
unit.declarations.add(classNode);
ClassElement classElement = ElementFactory.classElement2(className);
classNode.name.staticElement = classElement;
(unit.element as CompilationUnitElementImpl).types =
<ClassElement>[classElement];
return classNode;
}
CompilationUnit _createResolvedCompilationUnit() {
CompilationUnit unit = AstFactory.compilationUnit();
LibraryElementImpl library =
ElementFactory.library(AnalysisContextFactory.contextWithCore(), "lib");
unit.element = library.definingCompilationUnit;
return unit;
}
ConstructorDeclaration _createResolvedConstructorDeclaration() {
ClassDeclaration classNode = _createResolvedClassDeclaration();
String constructorName = "f";
ConstructorDeclaration constructorNode = AstFactory.constructorDeclaration(
AstFactory.identifier3(constructorName),
null,
AstFactory.formalParameterList(),
null);
classNode.members.add(constructorNode);
ConstructorElement constructorElement =
ElementFactory.constructorElement2(classNode.element, null);
constructorNode.element = constructorElement;
(classNode.element as ClassElementImpl).constructors =
<ConstructorElement>[constructorElement];
return constructorNode;
}
FunctionDeclaration _createResolvedFunctionDeclaration() {
CompilationUnit unit = _createResolvedCompilationUnit();
String functionName = "f";
FunctionDeclaration functionNode = AstFactory.functionDeclaration(
null,
null,
functionName,
AstFactory.functionExpression());
unit.declarations.add(functionNode);
FunctionElement functionElement =
ElementFactory.functionElement(functionName);
functionNode.name.staticElement = functionElement;
(unit.element as CompilationUnitElementImpl).functions =
<FunctionElement>[functionElement];
return functionNode;
}
FunctionTypeAlias _createResolvedFunctionTypeAlias() {
CompilationUnit unit = _createResolvedCompilationUnit();
FunctionTypeAlias aliasNode = AstFactory.typeAlias(
AstFactory.typeName4("A"),
"F",
AstFactory.typeParameterList(),
AstFactory.formalParameterList());
unit.declarations.add(aliasNode);
SimpleIdentifier aliasName = aliasNode.name;
FunctionTypeAliasElement aliasElement =
new FunctionTypeAliasElementImpl.forNode(aliasName);
aliasName.staticElement = aliasElement;
(unit.element as CompilationUnitElementImpl).typeAliases =
<FunctionTypeAliasElement>[aliasElement];
return aliasNode;
}
MethodDeclaration _createResolvedMethodDeclaration() {
ClassDeclaration classNode = _createResolvedClassDeclaration();
String methodName = "f";
MethodDeclaration methodNode = AstFactory.methodDeclaration(
null,
null,
null,
null,
AstFactory.identifier3(methodName),
AstFactory.formalParameterList());
classNode.members.add(methodNode);
MethodElement methodElement =
ElementFactory.methodElement(methodName, null);
methodNode.name.staticElement = methodElement;
(classNode.element as ClassElementImpl).methods =
<MethodElement>[methodElement];
return methodNode;
}
Scope _scopeFor(AstNode node) {
return ResolutionContextBuilder.contextFor(node, listener).scope;
}
}
class _Edit {
final int offset;
final int length;
final String replacement;
_Edit(this.offset, this.length, this.replacement);
}