| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * This library contains the infrastructure to parse and integrate patch files. | 6 * This library contains the infrastructure to parse and integrate patch files. |
| 7 * | 7 * |
| 8 * Three types of elements can be patched: [LibraryElement], [ClassElement], | 8 * Three types of elements can be patched: [LibraryElement], [ClassElement], |
| 9 * [FunctionElement]. Patches are introduced in patch libraries which are loaded | 9 * [FunctionElement]. Patches are introduced in patch libraries which are loaded |
| 10 * together with the corresponding origin library. Which libraries that are | 10 * together with the corresponding origin library. Which libraries that are |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 | 327 |
| 328 void addLibraryTag(tree.LibraryTag tag) { | 328 void addLibraryTag(tree.LibraryTag tag) { |
| 329 super.addLibraryTag(tag); | 329 super.addLibraryTag(tag); |
| 330 imports.addLast(tag); | 330 imports.addLast(tag); |
| 331 } | 331 } |
| 332 | 332 |
| 333 void pushElement(Element patch) { | 333 void pushElement(Element patch) { |
| 334 if (isMemberPatch || (isClassPatch && patch is ClassElement)) { | 334 if (isMemberPatch || (isClassPatch && patch is ClassElement)) { |
| 335 // Apply patch. | 335 // Apply patch. |
| 336 patch.addMetadata(popMetadataHack()); | 336 patch.addMetadata(popMetadataHack()); |
| 337 LibraryElement originLibrary = compilationUnitElement.getLibrary(); | 337 LibraryElement originLibrary = compilationUnitElement.library; |
| 338 assert(originLibrary.isPatched); | 338 assert(originLibrary.isPatched); |
| 339 Element origin = originLibrary.localLookup(patch.name); | 339 Element origin = originLibrary.localLookup(patch.name); |
| 340 patchElement(listener, origin, patch); | 340 patchElement(listener, origin, patch); |
| 341 } | 341 } |
| 342 super.pushElement(patch); | 342 super.pushElement(patch); |
| 343 } | 343 } |
| 344 } | 344 } |
| 345 | 345 |
| 346 /** | 346 /** |
| 347 * Extension of [MemberListener] for parsing patch class bodies. | 347 * Extension of [MemberListener] for parsing patch class bodies. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 } | 397 } |
| 398 | 398 |
| 399 void patchElement(leg.DiagnosticListener listener, | 399 void patchElement(leg.DiagnosticListener listener, |
| 400 Element origin, | 400 Element origin, |
| 401 Element patch) { | 401 Element patch) { |
| 402 if (origin == null) { | 402 if (origin == null) { |
| 403 listener.reportError( | 403 listener.reportError( |
| 404 patch, leg.MessageKind.PATCH_NON_EXISTING, {'name': patch.name}); | 404 patch, leg.MessageKind.PATCH_NON_EXISTING, {'name': patch.name}); |
| 405 return; | 405 return; |
| 406 } | 406 } |
| 407 if (!(origin.isClass() || | 407 if (!(origin.isClass || |
| 408 origin.isConstructor() || | 408 origin.isConstructor || |
| 409 origin.isFunction() || | 409 origin.isFunction || |
| 410 origin.isAbstractField())) { | 410 origin.isAbstractField)) { |
| 411 // TODO(ahe): Remove this error when the parser rejects all bad modifiers. | 411 // TODO(ahe): Remove this error when the parser rejects all bad modifiers. |
| 412 listener.reportError(origin, leg.MessageKind.PATCH_NONPATCHABLE); | 412 listener.reportError(origin, leg.MessageKind.PATCH_NONPATCHABLE); |
| 413 return; | 413 return; |
| 414 } | 414 } |
| 415 if (patch.isClass()) { | 415 if (patch.isClass) { |
| 416 tryPatchClass(listener, origin, patch); | 416 tryPatchClass(listener, origin, patch); |
| 417 } else if (patch.isGetter()) { | 417 } else if (patch.isGetter) { |
| 418 tryPatchGetter(listener, origin, patch); | 418 tryPatchGetter(listener, origin, patch); |
| 419 } else if (patch.isSetter()) { | 419 } else if (patch.isSetter) { |
| 420 tryPatchSetter(listener, origin, patch); | 420 tryPatchSetter(listener, origin, patch); |
| 421 } else if (patch.isConstructor()) { | 421 } else if (patch.isConstructor) { |
| 422 tryPatchConstructor(listener, origin, patch); | 422 tryPatchConstructor(listener, origin, patch); |
| 423 } else if(patch.isFunction()) { | 423 } else if(patch.isFunction) { |
| 424 tryPatchFunction(listener, origin, patch); | 424 tryPatchFunction(listener, origin, patch); |
| 425 } else { | 425 } else { |
| 426 // TODO(ahe): Remove this error when the parser rejects all bad modifiers. | 426 // TODO(ahe): Remove this error when the parser rejects all bad modifiers. |
| 427 listener.reportError(patch, leg.MessageKind.PATCH_NONPATCHABLE); | 427 listener.reportError(patch, leg.MessageKind.PATCH_NONPATCHABLE); |
| 428 } | 428 } |
| 429 } | 429 } |
| 430 | 430 |
| 431 void tryPatchClass(leg.DiagnosticListener listener, | 431 void tryPatchClass(leg.DiagnosticListener listener, |
| 432 Element origin, | 432 Element origin, |
| 433 ClassElement patch) { | 433 ClassElement patch) { |
| 434 if (!origin.isClass()) { | 434 if (!origin.isClass) { |
| 435 listener.reportError( | 435 listener.reportError( |
| 436 origin, leg.MessageKind.PATCH_NON_CLASS, {'className': patch.name}); | 436 origin, leg.MessageKind.PATCH_NON_CLASS, {'className': patch.name}); |
| 437 listener.reportInfo( | 437 listener.reportInfo( |
| 438 patch, leg.MessageKind.PATCH_POINT_TO_CLASS, {'className': patch.name}); | 438 patch, leg.MessageKind.PATCH_POINT_TO_CLASS, {'className': patch.name}); |
| 439 return; | 439 return; |
| 440 } | 440 } |
| 441 patchClass(listener, origin, patch); | 441 patchClass(listener, origin, patch); |
| 442 } | 442 } |
| 443 | 443 |
| 444 void patchClass(leg.DiagnosticListener listener, | 444 void patchClass(leg.DiagnosticListener listener, |
| 445 ClassElementX origin, | 445 ClassElementX origin, |
| 446 ClassElementX patch) { | 446 ClassElementX patch) { |
| 447 if (origin.isPatched) { | 447 if (origin.isPatched) { |
| 448 listener.internalError(origin, | 448 listener.internalError(origin, |
| 449 "Patching the same class more than once."); | 449 "Patching the same class more than once."); |
| 450 } | 450 } |
| 451 origin.applyPatch(patch); | 451 origin.applyPatch(patch); |
| 452 } | 452 } |
| 453 | 453 |
| 454 void tryPatchGetter(leg.DiagnosticListener listener, | 454 void tryPatchGetter(leg.DiagnosticListener listener, |
| 455 Element origin, | 455 Element origin, |
| 456 FunctionElement patch) { | 456 FunctionElement patch) { |
| 457 if (!origin.isAbstractField()) { | 457 if (!origin.isAbstractField) { |
| 458 listener.reportError( | 458 listener.reportError( |
| 459 origin, leg.MessageKind.PATCH_NON_GETTER, {'name': origin.name}); | 459 origin, leg.MessageKind.PATCH_NON_GETTER, {'name': origin.name}); |
| 460 listener.reportInfo( | 460 listener.reportInfo( |
| 461 patch, | 461 patch, |
| 462 leg.MessageKind.PATCH_POINT_TO_GETTER, {'getterName': patch.name}); | 462 leg.MessageKind.PATCH_POINT_TO_GETTER, {'getterName': patch.name}); |
| 463 return; | 463 return; |
| 464 } | 464 } |
| 465 AbstractFieldElement originField = origin; | 465 AbstractFieldElement originField = origin; |
| 466 if (originField.getter == null) { | 466 if (originField.getter == null) { |
| 467 listener.reportError( | 467 listener.reportError( |
| 468 origin, leg.MessageKind.PATCH_NO_GETTER, {'getterName': patch.name}); | 468 origin, leg.MessageKind.PATCH_NO_GETTER, {'getterName': patch.name}); |
| 469 listener.reportInfo( | 469 listener.reportInfo( |
| 470 patch, | 470 patch, |
| 471 leg.MessageKind.PATCH_POINT_TO_GETTER, {'getterName': patch.name}); | 471 leg.MessageKind.PATCH_POINT_TO_GETTER, {'getterName': patch.name}); |
| 472 return; | 472 return; |
| 473 } | 473 } |
| 474 patchFunction(listener, originField.getter, patch); | 474 patchFunction(listener, originField.getter, patch); |
| 475 } | 475 } |
| 476 | 476 |
| 477 void tryPatchSetter(leg.DiagnosticListener listener, | 477 void tryPatchSetter(leg.DiagnosticListener listener, |
| 478 Element origin, | 478 Element origin, |
| 479 FunctionElement patch) { | 479 FunctionElement patch) { |
| 480 if (!origin.isAbstractField()) { | 480 if (!origin.isAbstractField) { |
| 481 listener.reportError( | 481 listener.reportError( |
| 482 origin, leg.MessageKind.PATCH_NON_SETTER, {'name': origin.name}); | 482 origin, leg.MessageKind.PATCH_NON_SETTER, {'name': origin.name}); |
| 483 listener.reportInfo( | 483 listener.reportInfo( |
| 484 patch, | 484 patch, |
| 485 leg.MessageKind.PATCH_POINT_TO_SETTER, {'setterName': patch.name}); | 485 leg.MessageKind.PATCH_POINT_TO_SETTER, {'setterName': patch.name}); |
| 486 return; | 486 return; |
| 487 } | 487 } |
| 488 AbstractFieldElement originField = origin; | 488 AbstractFieldElement originField = origin; |
| 489 if (originField.setter == null) { | 489 if (originField.setter == null) { |
| 490 listener.reportError( | 490 listener.reportError( |
| 491 origin, leg.MessageKind.PATCH_NO_SETTER, {'setterName': patch.name}); | 491 origin, leg.MessageKind.PATCH_NO_SETTER, {'setterName': patch.name}); |
| 492 listener.reportInfo( | 492 listener.reportInfo( |
| 493 patch, | 493 patch, |
| 494 leg.MessageKind.PATCH_POINT_TO_SETTER, {'setterName': patch.name}); | 494 leg.MessageKind.PATCH_POINT_TO_SETTER, {'setterName': patch.name}); |
| 495 return; | 495 return; |
| 496 } | 496 } |
| 497 patchFunction(listener, originField.setter, patch); | 497 patchFunction(listener, originField.setter, patch); |
| 498 } | 498 } |
| 499 | 499 |
| 500 void tryPatchConstructor(leg.DiagnosticListener listener, | 500 void tryPatchConstructor(leg.DiagnosticListener listener, |
| 501 Element origin, | 501 Element origin, |
| 502 FunctionElement patch) { | 502 FunctionElement patch) { |
| 503 if (!origin.isConstructor()) { | 503 if (!origin.isConstructor) { |
| 504 listener.reportError( | 504 listener.reportError( |
| 505 origin, | 505 origin, |
| 506 leg.MessageKind.PATCH_NON_CONSTRUCTOR, {'constructorName': patch.name}); | 506 leg.MessageKind.PATCH_NON_CONSTRUCTOR, {'constructorName': patch.name}); |
| 507 listener.reportInfo( | 507 listener.reportInfo( |
| 508 patch, | 508 patch, |
| 509 leg.MessageKind.PATCH_POINT_TO_CONSTRUCTOR, | 509 leg.MessageKind.PATCH_POINT_TO_CONSTRUCTOR, |
| 510 {'constructorName': patch.name}); | 510 {'constructorName': patch.name}); |
| 511 return; | 511 return; |
| 512 } | 512 } |
| 513 patchFunction(listener, origin, patch); | 513 patchFunction(listener, origin, patch); |
| 514 } | 514 } |
| 515 | 515 |
| 516 void tryPatchFunction(leg.DiagnosticListener listener, | 516 void tryPatchFunction(leg.DiagnosticListener listener, |
| 517 Element origin, | 517 Element origin, |
| 518 FunctionElement patch) { | 518 FunctionElement patch) { |
| 519 if (!origin.isFunction()) { | 519 if (!origin.isFunction) { |
| 520 listener.reportError( | 520 listener.reportError( |
| 521 origin, | 521 origin, |
| 522 leg.MessageKind.PATCH_NON_FUNCTION, {'functionName': patch.name}); | 522 leg.MessageKind.PATCH_NON_FUNCTION, {'functionName': patch.name}); |
| 523 listener.reportInfo( | 523 listener.reportInfo( |
| 524 patch, | 524 patch, |
| 525 leg.MessageKind.PATCH_POINT_TO_FUNCTION, {'functionName': patch.name}); | 525 leg.MessageKind.PATCH_POINT_TO_FUNCTION, {'functionName': patch.name}); |
| 526 return; | 526 return; |
| 527 } | 527 } |
| 528 patchFunction(listener, origin, patch); | 528 patchFunction(listener, origin, patch); |
| 529 } | 529 } |
| 530 | 530 |
| 531 void patchFunction(leg.DiagnosticListener listener, | 531 void patchFunction(leg.DiagnosticListener listener, |
| 532 FunctionElementX origin, | 532 FunctionElementX origin, |
| 533 FunctionElementX patch) { | 533 FunctionElementX patch) { |
| 534 if (!origin.modifiers.isExternal()) { | 534 if (!origin.modifiers.isExternal) { |
| 535 listener.reportError(origin, leg.MessageKind.PATCH_NON_EXTERNAL); | 535 listener.reportError(origin, leg.MessageKind.PATCH_NON_EXTERNAL); |
| 536 listener.reportInfo( | 536 listener.reportInfo( |
| 537 patch, | 537 patch, |
| 538 leg.MessageKind.PATCH_POINT_TO_FUNCTION, {'functionName': patch.name}); | 538 leg.MessageKind.PATCH_POINT_TO_FUNCTION, {'functionName': patch.name}); |
| 539 return; | 539 return; |
| 540 } | 540 } |
| 541 if (origin.isPatched) { | 541 if (origin.isPatched) { |
| 542 listener.internalError(origin, | 542 listener.internalError(origin, |
| 543 "Trying to patch a function more than once."); | 543 "Trying to patch a function more than once."); |
| 544 } | 544 } |
| 545 if (origin.cachedNode != null) { | 545 if (origin.cachedNode != null) { |
| 546 listener.internalError(origin, | 546 listener.internalError(origin, |
| 547 "Trying to patch an already compiled function."); | 547 "Trying to patch an already compiled function."); |
| 548 } | 548 } |
| 549 origin.applyPatch(patch); | 549 origin.applyPatch(patch); |
| 550 } | 550 } |
| 551 | 551 |
| 552 // TODO(johnniwinther): Add unittest when patch is (real) metadata. | 552 // TODO(johnniwinther): Add unittest when patch is (real) metadata. |
| 553 bool isPatchElement(Element element) { | 553 bool isPatchElement(Element element) { |
| 554 // TODO(lrn): More checks needed if we introduce metadata for real. | 554 // TODO(lrn): More checks needed if we introduce metadata for real. |
| 555 // In that case, it must have the identifier "native" as metadata. | 555 // In that case, it must have the identifier "native" as metadata. |
| 556 for (Link link = element.metadata; !link.isEmpty; link = link.tail) { | 556 for (Link link = element.metadata; !link.isEmpty; link = link.tail) { |
| 557 if (link.head is PatchMetadataAnnotation) return true; | 557 if (link.head is PatchMetadataAnnotation) return true; |
| 558 } | 558 } |
| 559 return false; | 559 return false; |
| 560 } | 560 } |
| OLD | NEW |