| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2014, 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 import 'package:unittest/unittest.dart'; |
| 6 import 'package:analyzer/file_system/memory_file_system.dart'; |
| 7 import 'mock_sdk.dart'; |
| 8 import 'package:analyzer/src/generated/sdk.dart'; |
| 9 import 'package:analyzer/file_system/file_system.dart'; |
| 10 import 'package:analyzer/src/generated/source.dart'; |
| 11 import 'package:analyzer/src/generated/engine.dart'; |
| 12 import 'package:analyzer/src/generated/element.dart'; |
| 13 import 'package:analyzer/src/generated/source_io.dart'; |
| 14 import 'package:analyzer/analyzer.dart'; |
| 15 import 'package:analyzer2dart/src/identifier_semantics.dart'; |
| 16 |
| 17 main() { |
| 18 test('Call function defined at top level', () { |
| 19 Helper helper = new Helper(''' |
| 20 g() {} |
| 21 |
| 22 f() { |
| 23 g(); |
| 24 } |
| 25 '''); |
| 26 helper.checkStaticMethodInvocation('g()', null, 'g', true); |
| 27 }); |
| 28 |
| 29 test('Call function defined at top level via prefix', () { |
| 30 Helper helper = new Helper(''' |
| 31 import 'lib.dart' as l; |
| 32 |
| 33 f() { |
| 34 l.g(); |
| 35 } |
| 36 '''); |
| 37 helper.addFile('/lib.dart', ''' |
| 38 library lib; |
| 39 |
| 40 g() {} |
| 41 '''); |
| 42 helper.checkStaticMethodInvocation('l.g()', null, 'g', true); |
| 43 }); |
| 44 |
| 45 test('Call method defined statically in class from inside class', () { |
| 46 Helper helper = new Helper(''' |
| 47 class A { |
| 48 static g() {} |
| 49 |
| 50 f() { |
| 51 g(); |
| 52 } |
| 53 } |
| 54 '''); |
| 55 helper.checkStaticMethodInvocation('g()', 'A', 'g', true); |
| 56 }); |
| 57 |
| 58 test('Call method defined statically in class from outside class', () { |
| 59 Helper helper = new Helper(''' |
| 60 class A { |
| 61 static g() {} |
| 62 } |
| 63 f() { |
| 64 A.g(); |
| 65 } |
| 66 '''); |
| 67 helper.checkStaticMethodInvocation('A.g()', 'A', 'g', true); |
| 68 }); |
| 69 |
| 70 test('Call method defined dynamically in class from inside class', () { |
| 71 Helper helper = new Helper(''' |
| 72 class A { |
| 73 g() {} |
| 74 |
| 75 f() { |
| 76 g(); |
| 77 } |
| 78 } |
| 79 '''); |
| 80 helper.checkDynamicMethodInvocation('g()', null, 'g'); |
| 81 }); |
| 82 |
| 83 test( |
| 84 'Call method defined dynamically in class from outside class via typed var
', |
| 85 () { |
| 86 Helper helper = new Helper(''' |
| 87 class A { |
| 88 g() {} |
| 89 } |
| 90 f(A a) { |
| 91 a.g(); |
| 92 } |
| 93 '''); |
| 94 helper.checkDynamicMethodInvocation('a.g()', 'a', 'g'); |
| 95 }); |
| 96 |
| 97 test( |
| 98 'Call method defined dynamically in class from outside class via typed exp
ression', |
| 99 () { |
| 100 Helper helper = new Helper(''' |
| 101 class A { |
| 102 g() {} |
| 103 } |
| 104 A h() => null; |
| 105 f() { |
| 106 h().g(); |
| 107 } |
| 108 '''); |
| 109 helper.checkDynamicMethodInvocation('h().g()', 'h()', 'g'); |
| 110 }); |
| 111 |
| 112 test( |
| 113 'Call method defined dynamically in class from outside class via dynamic v
ar', |
| 114 () { |
| 115 Helper helper = new Helper(''' |
| 116 f(a) { |
| 117 a.g(); |
| 118 } |
| 119 '''); |
| 120 helper.checkDynamicMethodInvocation('a.g()', 'a', 'g'); |
| 121 }); |
| 122 |
| 123 test( |
| 124 'Call method defined dynamically in class from outside class via dynamic e
xpression', |
| 125 () { |
| 126 Helper helper = new Helper(''' |
| 127 h() => null; |
| 128 f() { |
| 129 h().g(); |
| 130 } |
| 131 '''); |
| 132 helper.checkDynamicMethodInvocation('h().g()', 'h()', 'g'); |
| 133 }); |
| 134 |
| 135 test('Call method defined locally', () { |
| 136 Helper helper = new Helper(''' |
| 137 f() { |
| 138 g() {} |
| 139 g(); |
| 140 } |
| 141 '''); |
| 142 helper.checkLocalFunctionInvocation('g()', 'g'); |
| 143 }); |
| 144 |
| 145 test('Call method undefined at top level', () { |
| 146 Helper helper = new Helper(''' |
| 147 f() { |
| 148 g(); |
| 149 } |
| 150 '''); |
| 151 // Undefined top level invocations are treated as DynamicMethodInvocation. |
| 152 // TODO(paulberry): not sure if this is a good idea. In general, when such |
| 153 // a call appears inside an instance method, it is dynamic, because "this" |
| 154 // might be an instance of a derived class that implements g(). However, |
| 155 // in this case, we are not inside an instance method, so we know that the |
| 156 // target is undefined. |
| 157 helper.checkDynamicMethodInvocation('g()', null, 'g'); |
| 158 }); |
| 159 |
| 160 test('Call method undefined at top level via prefix', () { |
| 161 Helper helper = new Helper(''' |
| 162 import 'lib.dart' as l; |
| 163 |
| 164 f() { |
| 165 l.g(); |
| 166 } |
| 167 '''); |
| 168 helper.addFile('/lib.dart', ''' |
| 169 library lib; |
| 170 '''); |
| 171 // Undefined top level invocations are treated as DynamicMethodInvocation. |
| 172 // TODO(paulberry): not sure if this is a good idea, for similar reasons to |
| 173 // the case above. |
| 174 helper.checkDynamicMethodInvocation('l.g()', null, 'g'); |
| 175 }); |
| 176 |
| 177 test('Call method undefined statically in class from outside class', () { |
| 178 Helper helper = new Helper(''' |
| 179 class A {} |
| 180 |
| 181 f() { |
| 182 A.g(); |
| 183 } |
| 184 '''); |
| 185 helper.checkStaticMethodInvocation('A.g()', 'A', 'g', false); |
| 186 }); |
| 187 |
| 188 test('Call method undefined dynamically in class from inside class', () { |
| 189 Helper helper = new Helper(''' |
| 190 class A { |
| 191 f() { |
| 192 g(); |
| 193 } |
| 194 } |
| 195 '''); |
| 196 helper.checkDynamicMethodInvocation('g()', null, 'g'); |
| 197 }); |
| 198 |
| 199 test( |
| 200 'Call method undefined dynamically in class from outside class via typed v
ar', |
| 201 () { |
| 202 Helper helper = new Helper(''' |
| 203 class A {} |
| 204 |
| 205 f(A a) { |
| 206 a.g(); |
| 207 } |
| 208 '''); |
| 209 helper.checkDynamicMethodInvocation('a.g()', 'a', 'g'); |
| 210 }); |
| 211 |
| 212 test( |
| 213 'Call method undefined dynamically in class from outside class via typed e
xpression', |
| 214 () { |
| 215 Helper helper = new Helper(''' |
| 216 class A {} |
| 217 |
| 218 A h() => null; |
| 219 |
| 220 f() { |
| 221 h().g(); |
| 222 } |
| 223 '''); |
| 224 helper.checkDynamicMethodInvocation('h().g()', 'h()', 'g'); |
| 225 }); |
| 226 |
| 227 test('Get variable defined at top level', () { |
| 228 Helper helper = new Helper(''' |
| 229 var x; |
| 230 |
| 231 f() { |
| 232 return x; |
| 233 } |
| 234 '''); |
| 235 helper.checkStaticFieldElementRef('x', null, 'x', true, false); |
| 236 }); |
| 237 |
| 238 test('Get variable defined at top level via prefix', () { |
| 239 Helper helper = new Helper(''' |
| 240 import 'lib.dart' as l; |
| 241 |
| 242 f() { |
| 243 return l.x; |
| 244 } |
| 245 '''); |
| 246 helper.addFile('/lib.dart', ''' |
| 247 library lib; |
| 248 |
| 249 var x; |
| 250 '''); |
| 251 helper.checkStaticFieldElementRef('l.x', null, 'x', true, false); |
| 252 }); |
| 253 |
| 254 test('Get field defined statically in class from inside class', () { |
| 255 Helper helper = new Helper(''' |
| 256 class A { |
| 257 static var x; |
| 258 |
| 259 f() { |
| 260 return x; |
| 261 } |
| 262 } |
| 263 '''); |
| 264 helper.checkStaticFieldElementRef('x', 'A', 'x', true, false); |
| 265 }); |
| 266 |
| 267 test('Get field defined statically in class from outside class', () { |
| 268 Helper helper = new Helper(''' |
| 269 class A { |
| 270 static var x; |
| 271 } |
| 272 |
| 273 f() { |
| 274 return A.x; |
| 275 } |
| 276 '''); |
| 277 helper.checkStaticFieldElementRef('A.x', 'A', 'x', true, false); |
| 278 }); |
| 279 |
| 280 test('Get field defined dynamically in class from inside class', () { |
| 281 Helper helper = new Helper(''' |
| 282 class A { |
| 283 var x; |
| 284 |
| 285 f() { |
| 286 return x; |
| 287 } |
| 288 } |
| 289 '''); |
| 290 helper.checkDynamicPropertyAccess('x', null, 'x', true, false); |
| 291 }); |
| 292 |
| 293 test( |
| 294 'Get field defined dynamically in class from outside class via typed var', |
| 295 () { |
| 296 Helper helper = new Helper(''' |
| 297 class A { |
| 298 var x; |
| 299 } |
| 300 |
| 301 f(A a) { |
| 302 return a.x; |
| 303 } |
| 304 '''); |
| 305 helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, false); |
| 306 }); |
| 307 |
| 308 test( |
| 309 'Get field defined dynamically in class from outside class via typed expre
ssion', |
| 310 () { |
| 311 Helper helper = new Helper(''' |
| 312 class A { |
| 313 var x; |
| 314 } |
| 315 |
| 316 A h() => null; |
| 317 |
| 318 f() { |
| 319 return h().x; |
| 320 } |
| 321 '''); |
| 322 helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, false); |
| 323 }); |
| 324 |
| 325 test( |
| 326 'Get field defined dynamically in class from outside class via dynamic var
', |
| 327 () { |
| 328 Helper helper = new Helper(''' |
| 329 f(a) { |
| 330 return a.x; |
| 331 } |
| 332 '''); |
| 333 helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, false); |
| 334 }); |
| 335 |
| 336 test( |
| 337 'Get field defined dynamically in class from outside class via dynamic exp
ression', |
| 338 () { |
| 339 Helper helper = new Helper(''' |
| 340 h() => null; |
| 341 |
| 342 f() { |
| 343 return h().x; |
| 344 } |
| 345 '''); |
| 346 helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, false); |
| 347 }); |
| 348 |
| 349 test('Get variable defined locally', () { |
| 350 Helper helper = new Helper(''' |
| 351 f() { |
| 352 var x; |
| 353 return x; |
| 354 } |
| 355 '''); |
| 356 helper.checkLocalVariableAccess('x', true, false); |
| 357 }); |
| 358 |
| 359 test('Get accessor defined at top level', () { |
| 360 Helper helper = new Helper(''' |
| 361 get x => null; |
| 362 |
| 363 f() { |
| 364 return x; |
| 365 } |
| 366 '''); |
| 367 helper.checkStaticPropertyAccess('x', null, 'x', true, true, false); |
| 368 }); |
| 369 |
| 370 test('Get accessor defined at top level via prefix', () { |
| 371 Helper helper = new Helper(''' |
| 372 import 'lib.dart' as l; |
| 373 |
| 374 f() { |
| 375 return l.x; |
| 376 } |
| 377 '''); |
| 378 helper.addFile('/lib.dart', ''' |
| 379 library lib; |
| 380 |
| 381 get x => null; |
| 382 '''); |
| 383 helper.checkStaticPropertyAccess('l.x', null, 'x', true, true, false); |
| 384 }); |
| 385 |
| 386 test('Get accessor defined statically in class from inside class', () { |
| 387 Helper helper = new Helper(''' |
| 388 class A { |
| 389 static get x => null; |
| 390 |
| 391 f() { |
| 392 return x; |
| 393 } |
| 394 } |
| 395 '''); |
| 396 helper.checkStaticPropertyAccess('x', 'A', 'x', true, true, false); |
| 397 }); |
| 398 |
| 399 test('Get accessor defined statically in class from outside class', () { |
| 400 Helper helper = new Helper(''' |
| 401 class A { |
| 402 static get x => null; |
| 403 } |
| 404 |
| 405 f() { |
| 406 return A.x; |
| 407 } |
| 408 '''); |
| 409 helper.checkStaticPropertyAccess('A.x', 'A', 'x', true, true, false); |
| 410 }); |
| 411 |
| 412 test('Get accessor defined dynamically in class from inside class', () { |
| 413 Helper helper = new Helper(''' |
| 414 class A { |
| 415 get x => null; |
| 416 |
| 417 f() { |
| 418 return x; |
| 419 } |
| 420 } |
| 421 '''); |
| 422 helper.checkDynamicPropertyAccess('x', null, 'x', true, false); |
| 423 }); |
| 424 |
| 425 test( |
| 426 'Get accessor defined dynamically in class from outside class via typed va
r', |
| 427 () { |
| 428 Helper helper = new Helper(''' |
| 429 class A { |
| 430 get x => null; |
| 431 } |
| 432 |
| 433 f(A a) { |
| 434 return a.x; |
| 435 } |
| 436 '''); |
| 437 helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, false); |
| 438 }); |
| 439 |
| 440 test( |
| 441 'Get accessor defined dynamically in class from outside class via typed ex
pression', |
| 442 () { |
| 443 Helper helper = new Helper(''' |
| 444 class A { |
| 445 get x => null; |
| 446 } |
| 447 |
| 448 A h() => null; |
| 449 |
| 450 f() { |
| 451 return h().x; |
| 452 } |
| 453 '''); |
| 454 helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, false); |
| 455 }); |
| 456 |
| 457 test( |
| 458 'Get accessor defined dynamically in class from outside class via dynamic
var', |
| 459 () { |
| 460 Helper helper = new Helper(''' |
| 461 f(a) { |
| 462 return a.x; |
| 463 } |
| 464 '''); |
| 465 helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, false); |
| 466 }); |
| 467 |
| 468 test( |
| 469 'Get accessor defined dynamically in class from outside class via dynamic
expression', |
| 470 () { |
| 471 Helper helper = new Helper(''' |
| 472 h() => null; |
| 473 |
| 474 f() { |
| 475 return h().x; |
| 476 } |
| 477 '''); |
| 478 helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, false); |
| 479 }); |
| 480 |
| 481 test('Get accessor undefined at top level', () { |
| 482 Helper helper = new Helper(''' |
| 483 f() { |
| 484 return x; |
| 485 } |
| 486 '''); |
| 487 // Undefined top level property accesses are treated as |
| 488 // DynamicPropertyAccess. TODO(paulberry): not sure if this is a good |
| 489 // idea. In general, when such an access appears inside an instance |
| 490 // method, it is dynamic, because "this" might be an instance of a derived |
| 491 // class that implements x. However, in this case, we are not inside an |
| 492 // instance method, so we know that the target is undefined. |
| 493 helper.checkDynamicPropertyAccess('x', null, 'x', true, false); |
| 494 }); |
| 495 |
| 496 test('Get accessor undefined at top level via prefix', () { |
| 497 Helper helper = new Helper(''' |
| 498 import 'lib.dart' as l; |
| 499 |
| 500 f() { |
| 501 return l.x; |
| 502 } |
| 503 '''); |
| 504 helper.addFile('/lib.dart', ''' |
| 505 library lib; |
| 506 '''); |
| 507 // Undefined top level property accesses are treated as |
| 508 // DynamicPropertyAccess. TODO(paulberry): not sure if this is a good |
| 509 // idea, for similar reasons to the case above. |
| 510 helper.checkDynamicPropertyAccess('l.x', null, 'x', true, false); |
| 511 }); |
| 512 |
| 513 test('Get accessor undefined statically in class from outside class', () { |
| 514 Helper helper = new Helper(''' |
| 515 class A {} |
| 516 |
| 517 f() { |
| 518 return A.x; |
| 519 } |
| 520 '''); |
| 521 helper.checkStaticPropertyAccess('A.x', 'A', 'x', false, true, false); |
| 522 }); |
| 523 |
| 524 test('Get accessor undefined dynamically in class from inside class', () { |
| 525 Helper helper = new Helper(''' |
| 526 class A { |
| 527 f() { |
| 528 return x; |
| 529 } |
| 530 } |
| 531 '''); |
| 532 helper.checkDynamicPropertyAccess('x', null, 'x', true, false); |
| 533 }); |
| 534 |
| 535 test( |
| 536 'Get accessor undefined dynamically in class from outside class via typed
var', |
| 537 () { |
| 538 Helper helper = new Helper(''' |
| 539 class A {} |
| 540 |
| 541 f(A a) { |
| 542 return a.x; |
| 543 } |
| 544 '''); |
| 545 helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, false); |
| 546 }); |
| 547 |
| 548 test( |
| 549 'Get accessor undefined dynamically in class from outside class via typed
expression', |
| 550 () { |
| 551 Helper helper = new Helper(''' |
| 552 class A {} |
| 553 |
| 554 A h() => null; |
| 555 |
| 556 f() { |
| 557 return h().x; |
| 558 } |
| 559 '''); |
| 560 helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, false); |
| 561 }); |
| 562 |
| 563 test('Set variable defined at top level', () { |
| 564 Helper helper = new Helper(''' |
| 565 var x; |
| 566 |
| 567 f() { |
| 568 x = 1; |
| 569 } |
| 570 '''); |
| 571 helper.checkStaticFieldElementRef('x', null, 'x', false, true); |
| 572 }); |
| 573 |
| 574 test('Set variable defined at top level via prefix', () { |
| 575 Helper helper = new Helper(''' |
| 576 import 'lib.dart' as l; |
| 577 |
| 578 f() { |
| 579 l.x = 1; |
| 580 } |
| 581 '''); |
| 582 helper.addFile('/lib.dart', ''' |
| 583 library lib; |
| 584 |
| 585 var x; |
| 586 '''); |
| 587 helper.checkStaticFieldElementRef('l.x', null, 'x', false, true); |
| 588 }); |
| 589 |
| 590 test('Set field defined statically in class from inside class', () { |
| 591 Helper helper = new Helper(''' |
| 592 class A { |
| 593 static var x; |
| 594 |
| 595 f() { |
| 596 x = 1; |
| 597 } |
| 598 } |
| 599 '''); |
| 600 helper.checkStaticFieldElementRef('x', 'A', 'x', false, true); |
| 601 }); |
| 602 |
| 603 test('Set field defined statically in class from outside class', () { |
| 604 Helper helper = new Helper(''' |
| 605 class A { |
| 606 static var x; |
| 607 } |
| 608 |
| 609 f() { |
| 610 A.x = 1; |
| 611 } |
| 612 '''); |
| 613 helper.checkStaticFieldElementRef('A.x', 'A', 'x', false, true); |
| 614 }); |
| 615 |
| 616 test('Set field defined dynamically in class from inside class', () { |
| 617 Helper helper = new Helper(''' |
| 618 class A { |
| 619 var x; |
| 620 |
| 621 f() { |
| 622 x = 1; |
| 623 } |
| 624 } |
| 625 '''); |
| 626 helper.checkDynamicPropertyAccess('x', null, 'x', false, true); |
| 627 }); |
| 628 |
| 629 test( |
| 630 'Set field defined dynamically in class from outside class via typed var', |
| 631 () { |
| 632 Helper helper = new Helper(''' |
| 633 class A { |
| 634 var x; |
| 635 } |
| 636 |
| 637 f(A a) { |
| 638 a.x = 1; |
| 639 } |
| 640 '''); |
| 641 helper.checkDynamicPropertyAccess('a.x', 'a', 'x', false, true); |
| 642 }); |
| 643 |
| 644 test( |
| 645 'Set field defined dynamically in class from outside class via typed expre
ssion', |
| 646 () { |
| 647 Helper helper = new Helper(''' |
| 648 class A { |
| 649 var x; |
| 650 } |
| 651 |
| 652 A h() => null; |
| 653 |
| 654 f() { |
| 655 h().x = 1; |
| 656 } |
| 657 '''); |
| 658 helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', false, true); |
| 659 }); |
| 660 |
| 661 test('Set variable defined locally', () { |
| 662 Helper helper = new Helper(''' |
| 663 f() { |
| 664 var x; |
| 665 x = 1; |
| 666 } |
| 667 '''); |
| 668 helper.checkLocalVariableAccess('x', false, true); |
| 669 }); |
| 670 |
| 671 test('Set accessor defined at top level', () { |
| 672 Helper helper = new Helper(''' |
| 673 set x(value) {}; |
| 674 |
| 675 f() { |
| 676 x = 1; |
| 677 } |
| 678 '''); |
| 679 helper.checkStaticPropertyAccess('x', null, 'x', true, false, true); |
| 680 }); |
| 681 |
| 682 test('Set accessor defined at top level via prefix', () { |
| 683 Helper helper = new Helper(''' |
| 684 import 'lib.dart' as l; |
| 685 |
| 686 f() { |
| 687 l.x = 1; |
| 688 } |
| 689 '''); |
| 690 helper.addFile('/lib.dart', ''' |
| 691 library lib; |
| 692 |
| 693 set x(value) {}; |
| 694 '''); |
| 695 helper.checkStaticPropertyAccess('l.x', null, 'x', true, false, true); |
| 696 }); |
| 697 |
| 698 test('Set accessor defined statically in class from inside class', () { |
| 699 Helper helper = new Helper(''' |
| 700 class A { |
| 701 static set x(value) {} |
| 702 |
| 703 f() { |
| 704 x = 1; |
| 705 } |
| 706 } |
| 707 '''); |
| 708 helper.checkStaticPropertyAccess('x', 'A', 'x', true, false, true); |
| 709 }); |
| 710 |
| 711 test('Set accessor defined statically in class from outside class', () { |
| 712 Helper helper = new Helper(''' |
| 713 class A { |
| 714 static set x(value) {} |
| 715 } |
| 716 |
| 717 f() { |
| 718 A.x = 1; |
| 719 } |
| 720 '''); |
| 721 helper.checkStaticPropertyAccess('A.x', 'A', 'x', true, false, true); |
| 722 }); |
| 723 |
| 724 test('Set accessor defined dynamically in class from inside class', () { |
| 725 Helper helper = new Helper(''' |
| 726 class A { |
| 727 set x(value) {} |
| 728 |
| 729 f() { |
| 730 x = 1; |
| 731 } |
| 732 } |
| 733 '''); |
| 734 helper.checkDynamicPropertyAccess('x', null, 'x', false, true); |
| 735 }); |
| 736 |
| 737 test( |
| 738 'Set accessor defined dynamically in class from outside class via typed va
r', |
| 739 () { |
| 740 Helper helper = new Helper(''' |
| 741 class A { |
| 742 set x(value) {} |
| 743 } |
| 744 |
| 745 f(A a) { |
| 746 a.x = 1; |
| 747 } |
| 748 '''); |
| 749 helper.checkDynamicPropertyAccess('a.x', 'a', 'x', false, true); |
| 750 }); |
| 751 |
| 752 test( |
| 753 'Set accessor defined dynamically in class from outside class via typed ex
pression', |
| 754 () { |
| 755 Helper helper = new Helper(''' |
| 756 class A { |
| 757 set x(value) {} |
| 758 } |
| 759 |
| 760 A h() => null; |
| 761 |
| 762 f() { |
| 763 h().x = 1; |
| 764 } |
| 765 '''); |
| 766 helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', false, true); |
| 767 }); |
| 768 |
| 769 test( |
| 770 'Set accessor defined dynamically in class from outside class via dynamic
var', |
| 771 () { |
| 772 Helper helper = new Helper(''' |
| 773 f(a) { |
| 774 a.x = 1; |
| 775 } |
| 776 '''); |
| 777 helper.checkDynamicPropertyAccess('a.x', 'a', 'x', false, true); |
| 778 }); |
| 779 |
| 780 test( |
| 781 'Set accessor defined dynamically in class from outside class via dynamic
expression', |
| 782 () { |
| 783 Helper helper = new Helper(''' |
| 784 h() => null; |
| 785 |
| 786 f() { |
| 787 h().x = 1; |
| 788 } |
| 789 '''); |
| 790 helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', false, true); |
| 791 }); |
| 792 |
| 793 test('Set accessor undefined at top level', () { |
| 794 Helper helper = new Helper(''' |
| 795 f() { |
| 796 x = 1; |
| 797 } |
| 798 '''); |
| 799 helper.checkDynamicPropertyAccess('x', null, 'x', false, true); |
| 800 }); |
| 801 |
| 802 test('Set accessor undefined at top level via prefix', () { |
| 803 Helper helper = new Helper(''' |
| 804 import 'lib.dart' as l; |
| 805 |
| 806 f() { |
| 807 l.x = 1; |
| 808 } |
| 809 '''); |
| 810 helper.addFile('/lib.dart', ''' |
| 811 library lib; |
| 812 '''); |
| 813 helper.checkDynamicPropertyAccess('l.x', null, 'x', false, true); |
| 814 }); |
| 815 |
| 816 test('Set accessor undefined statically in class from outside class', () { |
| 817 Helper helper = new Helper(''' |
| 818 class A {} |
| 819 |
| 820 f() { |
| 821 A.x = 1; |
| 822 } |
| 823 '''); |
| 824 helper.checkStaticPropertyAccess('A.x', 'A', 'x', false, false, true); |
| 825 }); |
| 826 |
| 827 test('Set accessor undefined dynamically in class from inside class', () { |
| 828 Helper helper = new Helper(''' |
| 829 class A { |
| 830 f() { |
| 831 x = 1; |
| 832 } |
| 833 } |
| 834 '''); |
| 835 helper.checkDynamicPropertyAccess('x', null, 'x', false, true); |
| 836 }); |
| 837 |
| 838 test( |
| 839 'Set accessor undefined dynamically in class from outside class via typed
var', |
| 840 () { |
| 841 Helper helper = new Helper(''' |
| 842 class A {} |
| 843 |
| 844 f(A a) { |
| 845 a.x = 1; |
| 846 } |
| 847 '''); |
| 848 helper.checkDynamicPropertyAccess('a.x', 'a', 'x', false, true); |
| 849 }); |
| 850 |
| 851 test( |
| 852 'Set accessor undefined dynamically in class from outside class via typed
expression', |
| 853 () { |
| 854 Helper helper = new Helper(''' |
| 855 class A {} |
| 856 |
| 857 A h() => null; |
| 858 |
| 859 f() { |
| 860 h().x = 1; |
| 861 } |
| 862 '''); |
| 863 helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', false, true); |
| 864 }); |
| 865 |
| 866 test('RMW variable defined at top level', () { |
| 867 Helper helper = new Helper(''' |
| 868 var x; |
| 869 |
| 870 f() { |
| 871 x += 1; |
| 872 } |
| 873 '''); |
| 874 helper.checkStaticFieldElementRef('x', null, 'x', true, true); |
| 875 }); |
| 876 |
| 877 test('RMW variable defined at top level via prefix', () { |
| 878 Helper helper = new Helper(''' |
| 879 import 'lib.dart' as l; |
| 880 |
| 881 f() { |
| 882 l.x += 1; |
| 883 } |
| 884 '''); |
| 885 helper.addFile('/lib.dart', ''' |
| 886 library lib; |
| 887 |
| 888 var x; |
| 889 '''); |
| 890 helper.checkStaticFieldElementRef('l.x', null, 'x', true, true); |
| 891 }); |
| 892 |
| 893 test('RMW field defined statically in class from inside class', () { |
| 894 Helper helper = new Helper(''' |
| 895 class A { |
| 896 static var x; |
| 897 |
| 898 f() { |
| 899 x += 1; |
| 900 } |
| 901 } |
| 902 '''); |
| 903 helper.checkStaticFieldElementRef('x', 'A', 'x', true, true); |
| 904 }); |
| 905 |
| 906 test('RMW field defined statically in class from outside class', () { |
| 907 Helper helper = new Helper(''' |
| 908 class A { |
| 909 static var x; |
| 910 } |
| 911 |
| 912 f() { |
| 913 A.x += 1; |
| 914 } |
| 915 '''); |
| 916 helper.checkStaticFieldElementRef('A.x', 'A', 'x', true, true); |
| 917 }); |
| 918 |
| 919 test('RMW field defined dynamically in class from inside class', () { |
| 920 Helper helper = new Helper(''' |
| 921 class A { |
| 922 var x; |
| 923 |
| 924 f() { |
| 925 x += 1; |
| 926 } |
| 927 } |
| 928 '''); |
| 929 helper.checkDynamicPropertyAccess('x', null, 'x', true, true); |
| 930 }); |
| 931 |
| 932 test( |
| 933 'RMW field defined dynamically in class from outside class via typed var', |
| 934 () { |
| 935 Helper helper = new Helper(''' |
| 936 class A { |
| 937 var x; |
| 938 } |
| 939 |
| 940 f(A a) { |
| 941 a.x += 1; |
| 942 } |
| 943 '''); |
| 944 helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, true); |
| 945 }); |
| 946 |
| 947 test( |
| 948 'RMW field defined dynamically in class from outside class via typed expre
ssion', |
| 949 () { |
| 950 Helper helper = new Helper(''' |
| 951 class A { |
| 952 var x; |
| 953 } |
| 954 |
| 955 A h() => null; |
| 956 |
| 957 f() { |
| 958 h().x += 1; |
| 959 } |
| 960 '''); |
| 961 helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, true); |
| 962 }); |
| 963 |
| 964 test('RMW variable defined locally', () { |
| 965 Helper helper = new Helper(''' |
| 966 f() { |
| 967 var x; |
| 968 x += 1; |
| 969 } |
| 970 '''); |
| 971 helper.checkLocalVariableAccess('x', true, true); |
| 972 }); |
| 973 |
| 974 test('RMW accessor defined at top level', () { |
| 975 Helper helper = new Helper(''' |
| 976 set x(value) {}; |
| 977 |
| 978 f() { |
| 979 x += 1; |
| 980 } |
| 981 '''); |
| 982 helper.checkStaticPropertyAccess('x', null, 'x', true, true, true); |
| 983 }); |
| 984 |
| 985 test('RMW accessor defined at top level via prefix', () { |
| 986 Helper helper = new Helper(''' |
| 987 import 'lib.dart' as l; |
| 988 |
| 989 f() { |
| 990 l.x += 1; |
| 991 } |
| 992 '''); |
| 993 helper.addFile('/lib.dart', ''' |
| 994 library lib; |
| 995 |
| 996 set x(value) {}; |
| 997 '''); |
| 998 helper.checkStaticPropertyAccess('l.x', null, 'x', true, true, true); |
| 999 }); |
| 1000 |
| 1001 test('RMW accessor defined statically in class from inside class', () { |
| 1002 Helper helper = new Helper(''' |
| 1003 class A { |
| 1004 static set x(value) {} |
| 1005 |
| 1006 f() { |
| 1007 x += 1; |
| 1008 } |
| 1009 } |
| 1010 '''); |
| 1011 helper.checkStaticPropertyAccess('x', 'A', 'x', true, true, true); |
| 1012 }); |
| 1013 |
| 1014 test('RMW accessor defined statically in class from outside class', () { |
| 1015 Helper helper = new Helper(''' |
| 1016 class A { |
| 1017 static set x(value) {} |
| 1018 } |
| 1019 |
| 1020 f() { |
| 1021 A.x += 1; |
| 1022 } |
| 1023 '''); |
| 1024 helper.checkStaticPropertyAccess('A.x', 'A', 'x', true, true, true); |
| 1025 }); |
| 1026 |
| 1027 test('RMW accessor defined dynamically in class from inside class', () { |
| 1028 Helper helper = new Helper(''' |
| 1029 class A { |
| 1030 set x(value) {} |
| 1031 |
| 1032 f() { |
| 1033 x += 1; |
| 1034 } |
| 1035 } |
| 1036 '''); |
| 1037 helper.checkDynamicPropertyAccess('x', null, 'x', true, true); |
| 1038 }); |
| 1039 |
| 1040 test( |
| 1041 'RMW accessor defined dynamically in class from outside class via typed va
r', |
| 1042 () { |
| 1043 Helper helper = new Helper(''' |
| 1044 class A { |
| 1045 set x(value) {} |
| 1046 } |
| 1047 |
| 1048 f(A a) { |
| 1049 a.x += 1; |
| 1050 } |
| 1051 '''); |
| 1052 helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, true); |
| 1053 }); |
| 1054 |
| 1055 test( |
| 1056 'RMW accessor defined dynamically in class from outside class via typed ex
pression', |
| 1057 () { |
| 1058 Helper helper = new Helper(''' |
| 1059 class A { |
| 1060 set x(value) {} |
| 1061 } |
| 1062 |
| 1063 A h() => null; |
| 1064 |
| 1065 f() { |
| 1066 h().x += 1; |
| 1067 } |
| 1068 '''); |
| 1069 helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, true); |
| 1070 }); |
| 1071 |
| 1072 test( |
| 1073 'RMW accessor defined dynamically in class from outside class via dynamic
var', |
| 1074 () { |
| 1075 Helper helper = new Helper(''' |
| 1076 f(a) { |
| 1077 a.x += 1; |
| 1078 } |
| 1079 '''); |
| 1080 helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, true); |
| 1081 }); |
| 1082 |
| 1083 test( |
| 1084 'RMW accessor defined dynamically in class from outside class via dynamic
expression', |
| 1085 () { |
| 1086 Helper helper = new Helper(''' |
| 1087 h() => null; |
| 1088 |
| 1089 f() { |
| 1090 h().x += 1; |
| 1091 } |
| 1092 '''); |
| 1093 helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, true); |
| 1094 }); |
| 1095 |
| 1096 test('RMW accessor undefined at top level', () { |
| 1097 Helper helper = new Helper(''' |
| 1098 f() { |
| 1099 x += 1; |
| 1100 } |
| 1101 '''); |
| 1102 helper.checkDynamicPropertyAccess('x', null, 'x', true, true); |
| 1103 }); |
| 1104 |
| 1105 test('RMW accessor undefined at top level via prefix', () { |
| 1106 Helper helper = new Helper(''' |
| 1107 import 'lib.dart' as l; |
| 1108 |
| 1109 f() { |
| 1110 l.x += 1; |
| 1111 } |
| 1112 '''); |
| 1113 helper.addFile('/lib.dart', ''' |
| 1114 library lib; |
| 1115 '''); |
| 1116 helper.checkDynamicPropertyAccess('l.x', null, 'x', true, true); |
| 1117 }); |
| 1118 |
| 1119 test('RMW accessor undefined statically in class from outside class', () { |
| 1120 Helper helper = new Helper(''' |
| 1121 class A {} |
| 1122 |
| 1123 f() { |
| 1124 A.x += 1; |
| 1125 } |
| 1126 '''); |
| 1127 helper.checkStaticPropertyAccess('A.x', 'A', 'x', false, true, true); |
| 1128 }); |
| 1129 |
| 1130 test('RMW accessor undefined dynamically in class from inside class', () { |
| 1131 Helper helper = new Helper(''' |
| 1132 class A { |
| 1133 f() { |
| 1134 x += 1; |
| 1135 } |
| 1136 } |
| 1137 '''); |
| 1138 helper.checkDynamicPropertyAccess('x', null, 'x', true, true); |
| 1139 }); |
| 1140 |
| 1141 test( |
| 1142 'RMW accessor undefined dynamically in class from outside class via typed
var', |
| 1143 () { |
| 1144 Helper helper = new Helper(''' |
| 1145 class A {} |
| 1146 |
| 1147 f(A a) { |
| 1148 a.x += 1; |
| 1149 } |
| 1150 '''); |
| 1151 helper.checkDynamicPropertyAccess('a.x', 'a', 'x', true, true); |
| 1152 }); |
| 1153 |
| 1154 test( |
| 1155 'RMW accessor undefined dynamically in class from outside class via typed
expression', |
| 1156 () { |
| 1157 Helper helper = new Helper(''' |
| 1158 class A {} |
| 1159 |
| 1160 A h() => null; |
| 1161 |
| 1162 f() { |
| 1163 h().x += 1; |
| 1164 } |
| 1165 '''); |
| 1166 helper.checkDynamicPropertyAccess('h().x', 'h()', 'x', true, true); |
| 1167 }); |
| 1168 } |
| 1169 |
| 1170 class Helper { |
| 1171 final MemoryResourceProvider provider = new MemoryResourceProvider(); |
| 1172 Source rootSource; |
| 1173 AnalysisContext context; |
| 1174 |
| 1175 Helper(String rootContents) { |
| 1176 DartSdk sdk = new MockSdk(); |
| 1177 String rootFile = '/root.dart'; |
| 1178 File file = provider.newFile(rootFile, rootContents); |
| 1179 rootSource = file.createSource(); |
| 1180 context = AnalysisEngine.instance.createAnalysisContext(); |
| 1181 // Set up the source factory. |
| 1182 List<UriResolver> uriResolvers = [ |
| 1183 new ResourceUriResolver(provider), |
| 1184 new DartUriResolver(sdk)]; |
| 1185 context.sourceFactory = new SourceFactory(uriResolvers); |
| 1186 // add the Source |
| 1187 ChangeSet changeSet = new ChangeSet(); |
| 1188 changeSet.addedSource(rootSource); |
| 1189 context.applyChanges(changeSet); |
| 1190 } |
| 1191 |
| 1192 void addFile(String path, String contents) { |
| 1193 provider.newFile(path, contents); |
| 1194 } |
| 1195 |
| 1196 LibraryElement get libraryElement { |
| 1197 return context.computeLibraryElement(rootSource); |
| 1198 } |
| 1199 |
| 1200 /** |
| 1201 * Verify that the node represented by [expectedSource] is classified as |
| 1202 * a static field element reference. |
| 1203 */ |
| 1204 void checkStaticFieldElementRef(String expectedSource, String expectedClass, |
| 1205 String expectedName, bool expectedIsRead, bool expectedIsWrite) { |
| 1206 TestVisitor visitor = new TestVisitor(); |
| 1207 int count = 0; |
| 1208 visitor.onAccess = (Expression node, AccessSemantics semantics) { |
| 1209 count++; |
| 1210 expect(node.toSource(), equals(expectedSource)); |
| 1211 expect(semantics, new isInstanceOf<StaticFieldAccess>()); |
| 1212 if (semantics is StaticFieldAccess) { |
| 1213 expect(semantics.field.displayName, equals(expectedName)); |
| 1214 if (expectedClass == null) { |
| 1215 expect(semantics.classElement, isNull); |
| 1216 } else { |
| 1217 expect(semantics.classElement, isNotNull); |
| 1218 expect(semantics.classElement.displayName, equals(expectedClass)); |
| 1219 } |
| 1220 } |
| 1221 expect(semantics.isRead, equals(expectedIsRead)); |
| 1222 expect(semantics.isWrite, equals(expectedIsWrite)); |
| 1223 }; |
| 1224 libraryElement.unit.accept(visitor); |
| 1225 expect(count, equals(1)); |
| 1226 } |
| 1227 |
| 1228 /** |
| 1229 * Verify that the node represented by [expectedSource] is classified as |
| 1230 * a static property access. |
| 1231 */ |
| 1232 void checkStaticPropertyAccess(String expectedSource, String expectedClass, |
| 1233 String expectedName, bool defined, bool expectedIsRead, bool expectedIsWri
te) { |
| 1234 TestVisitor visitor = new TestVisitor(); |
| 1235 int count = 0; |
| 1236 visitor.onAccess = (Expression node, AccessSemantics semantics) { |
| 1237 count++; |
| 1238 expect(node.toSource(), equals(expectedSource)); |
| 1239 expect(semantics, new isInstanceOf<StaticPropertyAccess>()); |
| 1240 if (semantics is StaticPropertyAccess) { |
| 1241 expect(semantics.propertyName.name, equals(expectedName)); |
| 1242 if (expectedClass == null) { |
| 1243 expect(semantics.classElement, isNull); |
| 1244 } else { |
| 1245 expect(semantics.classElement, isNotNull); |
| 1246 expect(semantics.classElement.displayName, equals(expectedClass)); |
| 1247 } |
| 1248 if (defined) { |
| 1249 expect(semantics.property.displayName, equals(expectedName)); |
| 1250 } else { |
| 1251 expect(semantics.property, isNull); |
| 1252 } |
| 1253 } |
| 1254 expect(semantics.isRead, equals(expectedIsRead)); |
| 1255 expect(semantics.isWrite, equals(expectedIsWrite)); |
| 1256 }; |
| 1257 libraryElement.unit.accept(visitor); |
| 1258 expect(count, equals(1)); |
| 1259 } |
| 1260 |
| 1261 /** |
| 1262 * Verify that the node represented by [expectedSource] is classified as |
| 1263 * a static method invocation. |
| 1264 */ |
| 1265 void checkStaticMethodInvocation(String expectedSource, String expectedClass, |
| 1266 String expectedName, bool defined) { |
| 1267 TestVisitor visitor = new TestVisitor(); |
| 1268 int count = 0; |
| 1269 visitor.onMethodInvocation = |
| 1270 (MethodInvocation node, MethodInvocationSemantics semantics) { |
| 1271 count++; |
| 1272 expect(node.toSource(), equals(expectedSource)); |
| 1273 expect(semantics, new isInstanceOf<StaticMethodInvocation>()); |
| 1274 if (semantics is StaticMethodInvocation) { |
| 1275 expect(semantics.methodName.name, equals(expectedName)); |
| 1276 if (expectedClass == null) { |
| 1277 expect(semantics.classElement, isNull); |
| 1278 if (defined) { |
| 1279 expect( |
| 1280 semantics.methodElement, |
| 1281 new isInstanceOf<FunctionElement>()); |
| 1282 } |
| 1283 } else { |
| 1284 expect(semantics.classElement, isNotNull); |
| 1285 expect(semantics.classElement.displayName, equals(expectedClass)); |
| 1286 if (defined) { |
| 1287 expect(semantics.methodElement, new isInstanceOf<MethodElement>()); |
| 1288 } |
| 1289 } |
| 1290 if (defined) { |
| 1291 expect(semantics.methodElement.displayName, equals(expectedName)); |
| 1292 } else { |
| 1293 expect(semantics.methodElement, isNull); |
| 1294 } |
| 1295 } |
| 1296 }; |
| 1297 libraryElement.unit.accept(visitor); |
| 1298 expect(count, equals(1)); |
| 1299 } |
| 1300 |
| 1301 /** |
| 1302 * Verify that the node represented by [expectedSource] is classified as |
| 1303 * a dynamic method invocation. |
| 1304 */ |
| 1305 void checkDynamicMethodInvocation(String expectedSource, |
| 1306 String expectedTarget, String expectedName) { |
| 1307 TestVisitor visitor = new TestVisitor(); |
| 1308 int count = 0; |
| 1309 visitor.onMethodInvocation = |
| 1310 (MethodInvocation node, MethodInvocationSemantics semantics) { |
| 1311 count++; |
| 1312 expect(node.toSource(), equals(expectedSource)); |
| 1313 expect(semantics, new isInstanceOf<DynamicMethodInvocation>()); |
| 1314 if (semantics is DynamicMethodInvocation) { |
| 1315 if (expectedTarget == null) { |
| 1316 expect(semantics.target, isNull); |
| 1317 } else { |
| 1318 expect(semantics.target.toSource(), equals(expectedTarget)); |
| 1319 } |
| 1320 expect(semantics.methodName.name, equals(expectedName)); |
| 1321 } |
| 1322 }; |
| 1323 libraryElement.unit.accept(visitor); |
| 1324 expect(count, equals(1)); |
| 1325 } |
| 1326 |
| 1327 /** |
| 1328 * Verify that the node represented by [expectedSource] is classified as |
| 1329 * a local function invocation. |
| 1330 */ |
| 1331 void checkLocalFunctionInvocation(String expectedSource, |
| 1332 String expectedName) { |
| 1333 TestVisitor visitor = new TestVisitor(); |
| 1334 int count = 0; |
| 1335 visitor.onMethodInvocation = |
| 1336 (MethodInvocation node, MethodInvocationSemantics semantics) { |
| 1337 count++; |
| 1338 expect(node.toSource(), equals(expectedSource)); |
| 1339 expect(semantics, new isInstanceOf<LocalFunctionInvocation>()); |
| 1340 if (semantics is LocalFunctionInvocation) { |
| 1341 expect(semantics.functionElement.displayName, equals(expectedName)); |
| 1342 } |
| 1343 }; |
| 1344 libraryElement.unit.accept(visitor); |
| 1345 expect(count, equals(1)); |
| 1346 } |
| 1347 |
| 1348 /** |
| 1349 * Verify that the node represented by [expectedSource] is classified as |
| 1350 * a dynamic property access. |
| 1351 */ |
| 1352 void checkDynamicPropertyAccess(String expectedSource, String expectedTarget, |
| 1353 String expectedName, bool expectedIsRead, bool expectedIsWrite) { |
| 1354 TestVisitor visitor = new TestVisitor(); |
| 1355 int count = 0; |
| 1356 visitor.onAccess = (Expression node, AccessSemantics semantics) { |
| 1357 count++; |
| 1358 expect(node.toSource(), equals(expectedSource)); |
| 1359 expect(semantics, new isInstanceOf<DynamicPropertyAccess>()); |
| 1360 if (semantics is DynamicPropertyAccess) { |
| 1361 if (expectedTarget == null) { |
| 1362 expect(semantics.target, isNull); |
| 1363 } else { |
| 1364 expect(semantics.target.toSource(), equals(expectedTarget)); |
| 1365 } |
| 1366 expect(semantics.propertyName.name, equals(expectedName)); |
| 1367 } |
| 1368 expect(semantics.isRead, equals(expectedIsRead)); |
| 1369 expect(semantics.isWrite, equals(expectedIsWrite)); |
| 1370 }; |
| 1371 libraryElement.unit.accept(visitor); |
| 1372 expect(count, equals(1)); |
| 1373 } |
| 1374 |
| 1375 /** |
| 1376 * Verify that the node represented by [expectedSource] is classified as |
| 1377 * a local variable access. |
| 1378 */ |
| 1379 void checkLocalVariableAccess(String expectedName, bool expectedIsRead, |
| 1380 bool expectedIsWrite) { |
| 1381 TestVisitor visitor = new TestVisitor(); |
| 1382 int count = 0; |
| 1383 visitor.onAccess = (SimpleIdentifier node, AccessSemantics semantics) { |
| 1384 count++; |
| 1385 expect(node.name, equals(expectedName)); |
| 1386 expect(semantics, new isInstanceOf<LocalVariableAccess>()); |
| 1387 if (semantics is LocalVariableAccess) { |
| 1388 LocalVariableElement element = semantics.variable; |
| 1389 expect(element.name, equals(expectedName)); |
| 1390 } |
| 1391 expect(semantics.isRead, equals(expectedIsRead)); |
| 1392 expect(semantics.isWrite, equals(expectedIsWrite)); |
| 1393 }; |
| 1394 libraryElement.unit.accept(visitor); |
| 1395 expect(count, equals(1)); |
| 1396 } |
| 1397 } |
| 1398 |
| 1399 typedef void MethodInvocationHandler(MethodInvocation node, |
| 1400 MethodInvocationSemantics semantics); |
| 1401 typedef void AccessHandler(Expression node, AccessSemantics semantics); |
| 1402 |
| 1403 /** |
| 1404 * Visitor class used to run the tests. |
| 1405 */ |
| 1406 class TestVisitor extends RecursiveAstVisitor { |
| 1407 MethodInvocationHandler onMethodInvocation; |
| 1408 AccessHandler onAccess; |
| 1409 |
| 1410 @override |
| 1411 visitMethodInvocation(MethodInvocation node) { |
| 1412 onMethodInvocation(node, classifyMethodInvocation(node)); |
| 1413 } |
| 1414 |
| 1415 @override |
| 1416 visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 1417 onAccess(node, classifyPrefixedIdentifier(node)); |
| 1418 } |
| 1419 |
| 1420 @override |
| 1421 visitPropertyAccess(PropertyAccess node) { |
| 1422 onAccess(node, classifyPropertyAccess(node)); |
| 1423 } |
| 1424 |
| 1425 @override |
| 1426 visitSimpleIdentifier(SimpleIdentifier node) { |
| 1427 AccessSemantics semantics = classifyBareIdentifier(node); |
| 1428 if (semantics != null) { |
| 1429 onAccess(node, semantics); |
| 1430 } |
| 1431 } |
| 1432 } |
| OLD | NEW |