| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library engine.declaration_resolver_test; |
| 6 |
| 7 import 'package:analyzer/dart/ast/ast.dart'; |
| 8 import 'package:analyzer/dart/element/element.dart'; |
| 9 import 'package:analyzer/src/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/src/dart/ast/utilities.dart'; |
| 11 import 'package:analyzer/src/generated/engine.dart'; |
| 12 import 'package:analyzer/src/generated/resolver.dart'; |
| 13 import 'package:analyzer/src/generated/source.dart'; |
| 14 import 'package:analyzer/src/task/dart.dart'; |
| 15 import 'package:analyzer/task/dart.dart'; |
| 16 import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| 17 import 'package:unittest/unittest.dart'; |
| 18 |
| 19 import '../utils.dart'; |
| 20 import 'resolver_test_case.dart'; |
| 21 import 'test_support.dart'; |
| 22 |
| 23 main() { |
| 24 initializeTestEnvironment(); |
| 25 defineReflectiveTests(DeclarationResolverMetadataTest); |
| 26 defineReflectiveTests(DeclarationResolverTest); |
| 27 defineReflectiveTests(StrongModeDeclarationResolverTest); |
| 28 } |
| 29 |
| 30 CompilationUnit _cloneResolveUnit(CompilationUnit unit) { |
| 31 CompilationUnit clonedUnit = AstCloner.clone(unit); |
| 32 new DeclarationResolver().resolve(clonedUnit, unit.element); |
| 33 return clonedUnit; |
| 34 } |
| 35 |
| 36 SimpleIdentifier _findSimpleIdentifier( |
| 37 AstNode root, String code, String search) { |
| 38 return EngineTestCase.findNode( |
| 39 root, code, search, (n) => n is SimpleIdentifier); |
| 40 } |
| 41 |
| 42 @reflectiveTest |
| 43 class DeclarationResolverMetadataTest extends ResolverTestCase { |
| 44 String code; |
| 45 CompilationUnit unit; |
| 46 CompilationUnit unit2; |
| 47 |
| 48 void checkMetadata(String search) { |
| 49 NodeList<Annotation> metadata = _findMetadata(unit, search); |
| 50 NodeList<Annotation> metadata2 = _findMetadata(unit2, search); |
| 51 expect(metadata, isNotEmpty); |
| 52 for (int i = 0; i < metadata.length; i++) { |
| 53 expect( |
| 54 metadata2[i].elementAnnotation, same(metadata[i].elementAnnotation)); |
| 55 } |
| 56 } |
| 57 |
| 58 void setupCode(String code) { |
| 59 this.code = code; |
| 60 unit = resolveSource(code + ' const a = null;'); |
| 61 unit2 = _cloneResolveUnit(unit); |
| 62 } |
| 63 |
| 64 void test_metadata_classDeclaration() { |
| 65 setupCode('@a class C {}'); |
| 66 checkMetadata('C'); |
| 67 } |
| 68 |
| 69 void test_metadata_classTypeAlias() { |
| 70 setupCode('@a class C = D with E; class D {} class E {}'); |
| 71 checkMetadata('C'); |
| 72 } |
| 73 |
| 74 void test_metadata_constructorDeclaration_named() { |
| 75 setupCode('class C { @a C.x(); }'); |
| 76 checkMetadata('x'); |
| 77 } |
| 78 |
| 79 void test_metadata_constructorDeclaration_unnamed() { |
| 80 setupCode('class C { @a C(); }'); |
| 81 checkMetadata('C()'); |
| 82 } |
| 83 |
| 84 void test_metadata_declaredIdentifier() { |
| 85 setupCode('f(x, y) { for (@a var x in y) {} }'); |
| 86 checkMetadata('var'); |
| 87 } |
| 88 |
| 89 void test_metadata_enumDeclaration() { |
| 90 setupCode('@a enum E { v }'); |
| 91 checkMetadata('E'); |
| 92 } |
| 93 |
| 94 void test_metadata_exportDirective() { |
| 95 addNamedSource('/foo.dart', 'class C {}'); |
| 96 setupCode('@a export "foo.dart";'); |
| 97 checkMetadata('export'); |
| 98 } |
| 99 |
| 100 void test_metadata_fieldDeclaration() { |
| 101 setupCode('class C { @a int x; }'); |
| 102 checkMetadata('x'); |
| 103 } |
| 104 |
| 105 void test_metadata_fieldFormalParameter() { |
| 106 setupCode('class C { var x; C(@a this.x); }'); |
| 107 checkMetadata('this'); |
| 108 } |
| 109 |
| 110 void test_metadata_fieldFormalParameter_withDefault() { |
| 111 setupCode('class C { var x; C([@a this.x = null]); }'); |
| 112 checkMetadata('this'); |
| 113 } |
| 114 |
| 115 void test_metadata_functionDeclaration_function() { |
| 116 setupCode('@a f() {}'); |
| 117 checkMetadata('f'); |
| 118 } |
| 119 |
| 120 void test_metadata_functionDeclaration_getter() { |
| 121 setupCode('@a get f() => null;'); |
| 122 checkMetadata('f'); |
| 123 } |
| 124 |
| 125 void test_metadata_functionDeclaration_setter() { |
| 126 setupCode('@a set f(value) {}'); |
| 127 checkMetadata('f'); |
| 128 } |
| 129 |
| 130 void test_metadata_functionTypeAlias() { |
| 131 setupCode('@a typedef F();'); |
| 132 checkMetadata('F'); |
| 133 } |
| 134 |
| 135 void test_metadata_functionTypedFormalParameter() { |
| 136 setupCode('f(@a g()) {}'); |
| 137 checkMetadata('g'); |
| 138 } |
| 139 |
| 140 void test_metadata_functionTypedFormalParameter_withDefault() { |
| 141 setupCode('f([@a g() = null]) {}'); |
| 142 checkMetadata('g'); |
| 143 } |
| 144 |
| 145 void test_metadata_importDirective() { |
| 146 addNamedSource('/foo.dart', 'class C {}'); |
| 147 setupCode('@a import "foo.dart";'); |
| 148 checkMetadata('import'); |
| 149 } |
| 150 |
| 151 void test_metadata_importDirective_partiallyResolved() { |
| 152 addNamedSource('/foo.dart', 'class C {}'); |
| 153 this.code = 'const a = null; @a import "foo.dart";'; |
| 154 Source source = addNamedSource('/test.dart', code); |
| 155 LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| 156 analysisContext.computeResult(source, LIBRARY_ELEMENT1); |
| 157 unit = analysisContext.computeResult(target, RESOLVED_UNIT1); |
| 158 unit2 = _cloneResolveUnit(unit); |
| 159 checkMetadata('import'); |
| 160 } |
| 161 |
| 162 void test_metadata_libraryDirective() { |
| 163 setupCode('@a library L;'); |
| 164 checkMetadata('L'); |
| 165 } |
| 166 |
| 167 void test_metadata_localFunctionDeclaration() { |
| 168 setupCode('f() { @a g() {} }'); |
| 169 // Note: metadata on local function declarations is ignored by the |
| 170 // analyzer. TODO(paulberry): is this a bug? |
| 171 FunctionDeclaration node = EngineTestCase.findNode( |
| 172 unit, code, 'g', (AstNode n) => n is FunctionDeclaration); |
| 173 expect((node as FunctionDeclarationImpl).metadata, isEmpty); |
| 174 } |
| 175 |
| 176 void test_metadata_localVariableDeclaration() { |
| 177 setupCode('f() { @a int x; }'); |
| 178 checkMetadata('x'); |
| 179 } |
| 180 |
| 181 void test_metadata_methodDeclaration_getter() { |
| 182 setupCode('class C { @a get m => null; }'); |
| 183 checkMetadata('m'); |
| 184 } |
| 185 |
| 186 void test_metadata_methodDeclaration_method() { |
| 187 setupCode('class C { @a m() {} }'); |
| 188 checkMetadata('m'); |
| 189 } |
| 190 |
| 191 void test_metadata_methodDeclaration_setter() { |
| 192 setupCode('class C { @a set m(value) {} }'); |
| 193 checkMetadata('m'); |
| 194 } |
| 195 |
| 196 void test_metadata_partDirective() { |
| 197 addNamedSource('/foo.dart', 'part of L;'); |
| 198 setupCode('library L; @a part "foo.dart";'); |
| 199 checkMetadata('part'); |
| 200 } |
| 201 |
| 202 void test_metadata_simpleFormalParameter() { |
| 203 setupCode('f(@a x) {}) {}'); |
| 204 checkMetadata('x'); |
| 205 } |
| 206 |
| 207 void test_metadata_simpleFormalParameter_withDefault() { |
| 208 setupCode('f([@a x = null]) {}'); |
| 209 checkMetadata('x'); |
| 210 } |
| 211 |
| 212 void test_metadata_topLevelVariableDeclaration() { |
| 213 setupCode('@a int x;'); |
| 214 checkMetadata('x'); |
| 215 } |
| 216 |
| 217 void test_metadata_typeParameter_ofClass() { |
| 218 setupCode('class C<@a T> {}'); |
| 219 checkMetadata('T'); |
| 220 } |
| 221 |
| 222 void test_metadata_typeParameter_ofClassTypeAlias() { |
| 223 setupCode('class C<@a T> = D with E; class D {} class E {}'); |
| 224 checkMetadata('T'); |
| 225 } |
| 226 |
| 227 void test_metadata_typeParameter_ofFunction() { |
| 228 setupCode('f<@a T>() {}'); |
| 229 checkMetadata('T'); |
| 230 } |
| 231 |
| 232 void test_metadata_typeParameter_ofTypedef() { |
| 233 setupCode('typedef F<@a T>();'); |
| 234 checkMetadata('T'); |
| 235 } |
| 236 |
| 237 NodeList<Annotation> _findMetadata(CompilationUnit unit, String search) { |
| 238 AstNode node = |
| 239 EngineTestCase.findNode(unit, code, search, (AstNode _) => true); |
| 240 while (node != null) { |
| 241 if (node is AnnotatedNode && node.metadata.isNotEmpty) { |
| 242 return node.metadata; |
| 243 } |
| 244 if (node is NormalFormalParameter && node.metadata.isNotEmpty) { |
| 245 return node.metadata; |
| 246 } |
| 247 node = node.parent; |
| 248 } |
| 249 fail('Node not found'); |
| 250 return null; |
| 251 } |
| 252 } |
| 253 |
| 254 @reflectiveTest |
| 255 class DeclarationResolverTest extends ResolverTestCase { |
| 256 @override |
| 257 void setUp() { |
| 258 super.setUp(); |
| 259 } |
| 260 |
| 261 void test_enumConstant_partiallyResolved() { |
| 262 String code = r''' |
| 263 enum Fruit {apple, pear} |
| 264 '''; |
| 265 Source source = addNamedSource('/test.dart', code); |
| 266 LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| 267 analysisContext.computeResult(source, LIBRARY_ELEMENT1); |
| 268 CompilationUnit unit = |
| 269 analysisContext.computeResult(target, RESOLVED_UNIT1); |
| 270 _cloneResolveUnit(unit); |
| 271 } |
| 272 |
| 273 void test_functionDeclaration_getter() { |
| 274 String code = r''' |
| 275 int get zzz => 42; |
| 276 '''; |
| 277 CompilationUnit unit = resolveSource(code); |
| 278 PropertyAccessorElement getterElement = |
| 279 _findSimpleIdentifier(unit, code, 'zzz =>').staticElement; |
| 280 expect(getterElement.isGetter, isTrue); |
| 281 // re-resolve |
| 282 CompilationUnit unit2 = _cloneResolveUnit(unit); |
| 283 SimpleIdentifier getterName = _findSimpleIdentifier(unit2, code, 'zzz =>'); |
| 284 expect(getterName.staticElement, same(getterElement)); |
| 285 } |
| 286 |
| 287 void test_functionDeclaration_setter() { |
| 288 String code = r''' |
| 289 void set zzz(_) {} |
| 290 '''; |
| 291 CompilationUnit unit = resolveSource(code); |
| 292 PropertyAccessorElement setterElement = |
| 293 _findSimpleIdentifier(unit, code, 'zzz(_)').staticElement; |
| 294 expect(setterElement.isSetter, isTrue); |
| 295 // re-resolve |
| 296 CompilationUnit unit2 = _cloneResolveUnit(unit); |
| 297 SimpleIdentifier getterName = _findSimpleIdentifier(unit2, code, 'zzz(_)'); |
| 298 expect(getterName.staticElement, same(setterElement)); |
| 299 } |
| 300 |
| 301 void test_invalid_functionDeclaration_getter_inFunction() { |
| 302 String code = r''' |
| 303 main() { |
| 304 int get zzz => 42; |
| 305 } |
| 306 '''; |
| 307 CompilationUnit unit = resolveSource(code); |
| 308 FunctionElement getterElement = |
| 309 _findSimpleIdentifier(unit, code, 'zzz =>').staticElement; |
| 310 // re-resolve |
| 311 CompilationUnit unit2 = _cloneResolveUnit(unit); |
| 312 SimpleIdentifier getterName = _findSimpleIdentifier(unit2, code, 'zzz =>'); |
| 313 expect(getterName.staticElement, same(getterElement)); |
| 314 } |
| 315 |
| 316 void test_invalid_functionDeclaration_setter_inFunction() { |
| 317 String code = r''' |
| 318 main() { |
| 319 set zzz(x) {} |
| 320 } |
| 321 '''; |
| 322 CompilationUnit unit = resolveSource(code); |
| 323 FunctionElement setterElement = |
| 324 _findSimpleIdentifier(unit, code, 'zzz(x)').staticElement; |
| 325 // re-resolve |
| 326 CompilationUnit unit2 = _cloneResolveUnit(unit); |
| 327 SimpleIdentifier setterName = _findSimpleIdentifier(unit2, code, 'zzz(x)'); |
| 328 expect(setterName.staticElement, same(setterElement)); |
| 329 } |
| 330 |
| 331 void test_visitExportDirective_notExistingSource() { |
| 332 String code = r''' |
| 333 export 'foo.dart'; |
| 334 '''; |
| 335 CompilationUnit unit = resolveSource(code); |
| 336 // re-resolve |
| 337 _cloneResolveUnit(unit); |
| 338 // no other validations than built into DeclarationResolver |
| 339 } |
| 340 |
| 341 void test_visitExportDirective_unresolvedUri() { |
| 342 String code = r''' |
| 343 export 'package:foo/bar.dart'; |
| 344 '''; |
| 345 CompilationUnit unit = resolveSource(code); |
| 346 // re-resolve |
| 347 _cloneResolveUnit(unit); |
| 348 // no other validations than built into DeclarationResolver |
| 349 } |
| 350 |
| 351 void test_visitFunctionExpression() { |
| 352 String code = r''' |
| 353 main(List<String> items) { |
| 354 items.forEach((item) {}); |
| 355 } |
| 356 '''; |
| 357 CompilationUnit unit = resolveSource(code); |
| 358 // re-resolve |
| 359 _cloneResolveUnit(unit); |
| 360 // no other validations than built into DeclarationResolver |
| 361 } |
| 362 |
| 363 void test_visitImportDirective_notExistingSource() { |
| 364 String code = r''' |
| 365 import 'foo.dart'; |
| 366 '''; |
| 367 CompilationUnit unit = resolveSource(code); |
| 368 // re-resolve |
| 369 _cloneResolveUnit(unit); |
| 370 // no other validations than built into DeclarationResolver |
| 371 } |
| 372 |
| 373 void test_visitImportDirective_unresolvedUri() { |
| 374 String code = r''' |
| 375 import 'package:foo/bar.dart'; |
| 376 '''; |
| 377 CompilationUnit unit = resolveSource(code); |
| 378 // re-resolve |
| 379 _cloneResolveUnit(unit); |
| 380 // no other validations than built into DeclarationResolver |
| 381 } |
| 382 |
| 383 void test_visitMethodDeclaration_getter_duplicate() { |
| 384 String code = r''' |
| 385 class C { |
| 386 int get zzz => 1; |
| 387 String get zzz => null; |
| 388 } |
| 389 '''; |
| 390 CompilationUnit unit = resolveSource(code); |
| 391 PropertyAccessorElement firstElement = |
| 392 _findSimpleIdentifier(unit, code, 'zzz => 1').staticElement; |
| 393 PropertyAccessorElement secondElement = |
| 394 _findSimpleIdentifier(unit, code, 'zzz => null').staticElement; |
| 395 // re-resolve |
| 396 CompilationUnit unit2 = _cloneResolveUnit(unit); |
| 397 SimpleIdentifier firstName = _findSimpleIdentifier(unit2, code, 'zzz => 1'); |
| 398 SimpleIdentifier secondName = |
| 399 _findSimpleIdentifier(unit2, code, 'zzz => null'); |
| 400 expect(firstName.staticElement, same(firstElement)); |
| 401 expect(secondName.staticElement, same(secondElement)); |
| 402 } |
| 403 |
| 404 void test_visitMethodDeclaration_getterSetter() { |
| 405 String code = r''' |
| 406 class C { |
| 407 int _field = 0; |
| 408 int get field => _field; |
| 409 void set field(value) {_field = value;} |
| 410 } |
| 411 '''; |
| 412 CompilationUnit unit = resolveSource(code); |
| 413 FieldElement getterElement = |
| 414 _findSimpleIdentifier(unit, code, 'field =').staticElement; |
| 415 PropertyAccessorElement setterElement = |
| 416 _findSimpleIdentifier(unit, code, 'field(').staticElement; |
| 417 // re-resolve |
| 418 CompilationUnit unit2 = _cloneResolveUnit(unit); |
| 419 SimpleIdentifier getterName = _findSimpleIdentifier(unit2, code, 'field ='); |
| 420 SimpleIdentifier setterName = _findSimpleIdentifier(unit2, code, 'field('); |
| 421 expect(getterName.staticElement, same(getterElement)); |
| 422 expect(setterName.staticElement, same(setterElement)); |
| 423 } |
| 424 |
| 425 void test_visitMethodDeclaration_method_duplicate() { |
| 426 String code = r''' |
| 427 class C { |
| 428 void zzz(x) {} |
| 429 void zzz(y) {} |
| 430 } |
| 431 '''; |
| 432 CompilationUnit unit = resolveSource(code); |
| 433 MethodElement firstElement = |
| 434 _findSimpleIdentifier(unit, code, 'zzz(x)').staticElement; |
| 435 MethodElement secondElement = |
| 436 _findSimpleIdentifier(unit, code, 'zzz(y)').staticElement; |
| 437 // re-resolve |
| 438 CompilationUnit unit2 = _cloneResolveUnit(unit); |
| 439 SimpleIdentifier firstName = _findSimpleIdentifier(unit2, code, 'zzz(x)'); |
| 440 SimpleIdentifier secondName = _findSimpleIdentifier(unit2, code, 'zzz(y)'); |
| 441 expect(firstName.staticElement, same(firstElement)); |
| 442 expect(secondName.staticElement, same(secondElement)); |
| 443 } |
| 444 |
| 445 void test_visitMethodDeclaration_setter_duplicate() { |
| 446 // https://github.com/dart-lang/sdk/issues/25601 |
| 447 String code = r''' |
| 448 class C { |
| 449 set zzz(x) {} |
| 450 set zzz(y) {} |
| 451 } |
| 452 '''; |
| 453 CompilationUnit unit = resolveSource(code); |
| 454 PropertyAccessorElement firstElement = |
| 455 _findSimpleIdentifier(unit, code, 'zzz(x)').staticElement; |
| 456 PropertyAccessorElement secondElement = |
| 457 _findSimpleIdentifier(unit, code, 'zzz(y)').staticElement; |
| 458 // re-resolve |
| 459 CompilationUnit unit2 = _cloneResolveUnit(unit); |
| 460 SimpleIdentifier firstName = _findSimpleIdentifier(unit2, code, 'zzz(x)'); |
| 461 SimpleIdentifier secondName = _findSimpleIdentifier(unit2, code, 'zzz(y)'); |
| 462 expect(firstName.staticElement, same(firstElement)); |
| 463 expect(secondName.staticElement, same(secondElement)); |
| 464 } |
| 465 |
| 466 void test_visitMethodDeclaration_unaryMinus() { |
| 467 String code = r''' |
| 468 class C { |
| 469 C operator -() => null; |
| 470 C operator -(C other) => null; |
| 471 } |
| 472 '''; |
| 473 CompilationUnit unit = resolveSource(code); |
| 474 // re-resolve |
| 475 _cloneResolveUnit(unit); |
| 476 // no other validations than built into DeclarationResolver |
| 477 } |
| 478 |
| 479 void test_visitPartDirective_notExistingSource() { |
| 480 String code = r''' |
| 481 part 'foo.bar'; |
| 482 '''; |
| 483 CompilationUnit unit = resolveSource(code); |
| 484 // re-resolve |
| 485 _cloneResolveUnit(unit); |
| 486 // no other validations than built into DeclarationResolver |
| 487 } |
| 488 } |
| 489 |
| 490 /** |
| 491 * Strong mode DeclarationResolver tests |
| 492 */ |
| 493 @reflectiveTest |
| 494 class StrongModeDeclarationResolverTest extends ResolverTestCase { |
| 495 @override |
| 496 void setUp() { |
| 497 resetWithOptions(new AnalysisOptionsImpl()..strongMode = true); |
| 498 } |
| 499 |
| 500 void test_genericFunction_typeParameter() { |
| 501 String code = r''' |
| 502 /*=T*/ max/*<T>*/(/*=T*/ x, /*=T*/ y) => null; |
| 503 '''; |
| 504 CompilationUnit unit = resolveSource(code); |
| 505 FunctionDeclaration node = _findSimpleIdentifier(unit, code, 'max').parent; |
| 506 TypeParameter t = node.functionExpression.typeParameters.typeParameters[0]; |
| 507 |
| 508 FunctionElement element = node.name.staticElement; |
| 509 TypeParameterElement tElement = element.typeParameters[0]; |
| 510 expect(tElement, isNotNull); |
| 511 expect(element.typeParameters.toString(), "[T]"); |
| 512 expect(element.type.toString(), "<T>(T, T) → T"); |
| 513 expect(t.element, same(tElement)); |
| 514 |
| 515 // re-resolve |
| 516 CompilationUnit unit2 = _cloneResolveUnit(unit); |
| 517 node = _findSimpleIdentifier(unit2, code, 'max').parent; |
| 518 t = node.functionExpression.typeParameters.typeParameters[0]; |
| 519 expect(t.element, same(tElement)); |
| 520 } |
| 521 |
| 522 void test_genericMethod_typeParameter() { |
| 523 String code = r''' |
| 524 class C { |
| 525 /*=T*/ max/*<T>*/(/*=T*/ x, /*=T*/ y) => null; |
| 526 } |
| 527 '''; |
| 528 CompilationUnit unit = resolveSource(code); |
| 529 MethodDeclaration node = _findSimpleIdentifier(unit, code, 'max').parent; |
| 530 TypeParameter t = node.typeParameters.typeParameters[0]; |
| 531 |
| 532 MethodElement element = node.name.staticElement; |
| 533 TypeParameterElement tElement = element.typeParameters[0]; |
| 534 expect(tElement, isNotNull); |
| 535 expect(element.typeParameters.toString(), "[T]"); |
| 536 expect(element.type.toString(), "<T>(T, T) → T"); |
| 537 expect(t.element, same(tElement)); |
| 538 |
| 539 // re-resolve |
| 540 CompilationUnit unit2 = _cloneResolveUnit(unit); |
| 541 node = _findSimpleIdentifier(unit2, code, 'max').parent; |
| 542 t = node.typeParameters.typeParameters[0]; |
| 543 expect(t.element, same(tElement)); |
| 544 } |
| 545 } |
| OLD | NEW |