| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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 import 'package:front_end/src/fasta/scanner.dart' | 5 import 'package:front_end/src/fasta/scanner.dart' |
| 6 show BeginGroupToken, StringToken, Token; | 6 show BeginGroupToken, StringToken, Token; |
| 7 import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN; | 7 import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN; |
| 8 | 8 |
| 9 import '../common.dart'; | 9 import '../common.dart'; |
| 10 import '../common_elements.dart' show CommonElements; | 10 import '../common_elements.dart' show CommonElements, ElementEnvironment; |
| 11 import '../common/backend_api.dart'; | 11 import '../common/backend_api.dart'; |
| 12 import '../common/resolution.dart'; | 12 import '../common/resolution.dart'; |
| 13 import '../compiler.dart' show Compiler; | 13 import '../compiler.dart' show Compiler; |
| 14 import '../constants/values.dart'; | 14 import '../constants/values.dart'; |
| 15 import '../elements/elements.dart' | 15 import '../elements/elements.dart' |
| 16 show | 16 show |
| 17 ClassElement, | 17 ClassElement, |
| 18 Element, | 18 Element, |
| 19 FieldElement, | 19 FieldElement, |
| 20 LibraryElement, | |
| 21 MemberElement, | 20 MemberElement, |
| 22 MetadataAnnotation, | 21 MetadataAnnotation, |
| 23 MethodElement; | 22 MethodElement; |
| 24 import '../elements/entities.dart'; | 23 import '../elements/entities.dart'; |
| 25 import '../elements/modelx.dart' show FunctionElementX, MetadataAnnotationX; | 24 import '../elements/modelx.dart' show FunctionElementX, MetadataAnnotationX; |
| 26 import '../elements/resolution_types.dart' show ResolutionDartType; | 25 import '../elements/resolution_types.dart' show ResolutionDartType; |
| 27 import '../js_backend/js_backend.dart'; | 26 import '../js_backend/js_backend.dart'; |
| 28 import '../js_backend/native_data.dart'; | 27 import '../js_backend/native_data.dart'; |
| 29 import '../patch_parser.dart'; | 28 import '../patch_parser.dart'; |
| 30 import '../tree/tree.dart'; | 29 import '../tree/tree.dart'; |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 ResolutionDartType type = constant.getType(compiler.commonElements); | 337 ResolutionDartType type = constant.getType(compiler.commonElements); |
| 339 if (type.element != compiler.commonElements.jsAnnotationClass) { | 338 if (type.element != compiler.commonElements.jsAnnotationClass) { |
| 340 compiler.reporter | 339 compiler.reporter |
| 341 .internalError(annotation, 'Invalid @JS(...) annotation.'); | 340 .internalError(annotation, 'Invalid @JS(...) annotation.'); |
| 342 } | 341 } |
| 343 } | 342 } |
| 344 | 343 |
| 345 bool get defaultResult => false; | 344 bool get defaultResult => false; |
| 346 } | 345 } |
| 347 | 346 |
| 348 /// Interface for computing all native classes in a set of libraries. | 347 /// Determines all native classes in a set of libraries. |
| 349 abstract class NativeClassResolver { | 348 abstract class NativeClassFinder { |
| 349 /// Returns the set of all native classes declared in [libraries]. |
| 350 Iterable<ClassEntity> computeNativeClasses(Iterable<LibraryEntity> libraries); | 350 Iterable<ClassEntity> computeNativeClasses(Iterable<LibraryEntity> libraries); |
| 351 } | 351 } |
| 352 | 352 |
| 353 class NativeClassResolverImpl implements NativeClassResolver { | 353 class BaseNativeClassFinder implements NativeClassFinder { |
| 354 final DiagnosticReporter _reporter; | 354 final ElementEnvironment _elementEnvironment; |
| 355 final Resolution _resolution; | |
| 356 final CommonElements _commonElements; | 355 final CommonElements _commonElements; |
| 357 final NativeBasicData _nativeBasicData; | 356 final NativeBasicData _nativeBasicData; |
| 358 | 357 |
| 359 Map<String, ClassElement> _tagOwner = new Map<String, ClassElement>(); | 358 Map<String, ClassEntity> _tagOwner = new Map<String, ClassEntity>(); |
| 360 | 359 |
| 361 NativeClassResolverImpl(this._resolution, this._reporter, | 360 BaseNativeClassFinder( |
| 362 this._commonElements, this._nativeBasicData); | 361 this._elementEnvironment, this._commonElements, this._nativeBasicData); |
| 363 | 362 |
| 364 Iterable<ClassElement> computeNativeClasses( | 363 Iterable<ClassEntity> computeNativeClasses( |
| 365 Iterable<LibraryElement> libraries) { | 364 Iterable<LibraryEntity> libraries) { |
| 366 Set<ClassElement> nativeClasses = new Set<ClassElement>(); | 365 Set<ClassEntity> nativeClasses = new Set<ClassEntity>(); |
| 367 libraries.forEach((l) => _processNativeClassesInLibrary(l, nativeClasses)); | 366 libraries.forEach((l) => _processNativeClassesInLibrary(l, nativeClasses)); |
| 368 if (_commonElements.isolateHelperLibrary != null) { | 367 if (_commonElements.isolateHelperLibrary != null) { |
| 369 _processNativeClassesInLibrary( | 368 _processNativeClassesInLibrary( |
| 370 _commonElements.isolateHelperLibrary, nativeClasses); | 369 _commonElements.isolateHelperLibrary, nativeClasses); |
| 371 } | 370 } |
| 372 _processSubclassesOfNativeClasses(libraries, nativeClasses); | 371 _processSubclassesOfNativeClasses(libraries, nativeClasses); |
| 373 return nativeClasses; | 372 return nativeClasses; |
| 374 } | 373 } |
| 375 | 374 |
| 375 /// Adds all directly native classes declared in [library] to [nativeClasses]. |
| 376 void _processNativeClassesInLibrary( | 376 void _processNativeClassesInLibrary( |
| 377 LibraryElement library, Set<ClassElement> nativeClasses) { | 377 LibraryEntity library, Set<ClassEntity> nativeClasses) { |
| 378 // Use implementation to ensure the inclusion of injected members. | 378 _elementEnvironment.forEachClass(library, (ClassEntity cls) { |
| 379 library.implementation.forEachLocalMember((Element element) { | 379 if (_nativeBasicData.isNativeClass(cls)) { |
| 380 if (element.isClass) { | 380 _processNativeClass(cls, nativeClasses); |
| 381 ClassElement cls = element; | |
| 382 if (_nativeBasicData.isNativeClass(cls)) { | |
| 383 _processNativeClass(element, nativeClasses); | |
| 384 } | |
| 385 } | 381 } |
| 386 }); | 382 }); |
| 387 } | 383 } |
| 388 | 384 |
| 389 void _processNativeClass( | 385 /// Adds [cls] to [nativeClasses] and performs further processing of [cls], |
| 390 ClassElement classElement, Set<ClassElement> nativeClasses) { | 386 /// if necessary. |
| 391 nativeClasses.add(classElement); | 387 void _processNativeClass(ClassEntity cls, Set<ClassEntity> nativeClasses) { |
| 392 // Resolve class to ensure the class has valid inheritance info. | 388 nativeClasses.add(cls); |
| 393 classElement.ensureResolved(_resolution); | |
| 394 // Js Interop interfaces do not have tags. | 389 // Js Interop interfaces do not have tags. |
| 395 if (_nativeBasicData.isJsInteropClass(classElement)) return; | 390 if (_nativeBasicData.isJsInteropClass(cls)) return; |
| 396 // Since we map from dispatch tags to classes, a dispatch tag must be used | 391 // Since we map from dispatch tags to classes, a dispatch tag must be used |
| 397 // on only one native class. | 392 // on only one native class. |
| 398 for (String tag in _nativeBasicData.getNativeTagsOfClass(classElement)) { | 393 for (String tag in _nativeBasicData.getNativeTagsOfClass(cls)) { |
| 399 ClassElement owner = _tagOwner[tag]; | 394 ClassEntity owner = _tagOwner[tag]; |
| 400 if (owner != null) { | 395 if (owner != null) { |
| 401 if (owner != classElement) { | 396 if (owner != cls) { |
| 402 _reporter.internalError( | 397 throw new SpannableAssertionFailure( |
| 403 classElement, "Tag '$tag' already in use by '${owner.name}'"); | 398 cls, "Tag '$tag' already in use by '${owner.name}'"); |
| 404 } | 399 } |
| 405 } else { | 400 } else { |
| 406 _tagOwner[tag] = classElement; | 401 _tagOwner[tag] = cls; |
| 407 } | 402 } |
| 408 } | 403 } |
| 409 } | 404 } |
| 410 | 405 |
| 406 /// Returns the name of the super class of [cls] or `null` of [cls] has |
| 407 /// no explicit superclass. |
| 408 String _findExtendsNameOfClass(ClassEntity cls) { |
| 409 return _elementEnvironment.getSuperClass(cls)?.name; |
| 410 } |
| 411 |
| 412 /// Adds all subclasses of [nativeClasses] found in [libraries] to |
| 413 /// [nativeClasses]. |
| 411 void _processSubclassesOfNativeClasses( | 414 void _processSubclassesOfNativeClasses( |
| 412 Iterable<LibraryElement> libraries, Set<ClassElement> nativeClasses) { | 415 Iterable<LibraryEntity> libraries, Set<ClassEntity> nativeClasses) { |
| 413 Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>(); | 416 Set<ClassEntity> nativeClassesAndSubclasses = new Set<ClassEntity>(); |
| 414 // Collect potential subclasses, e.g. | 417 // Collect potential subclasses, e.g. |
| 415 // | 418 // |
| 416 // class B extends foo.A {} | 419 // class B extends foo.A {} |
| 417 // | 420 // |
| 418 // String "A" has a potential subclass B. | 421 // String "A" has a potential subclass B. |
| 419 | 422 |
| 420 var potentialExtends = new Map<String, Set<ClassElement>>(); | 423 Map<String, Set<ClassEntity>> potentialExtends = |
| 424 <String, Set<ClassEntity>>{}; |
| 421 | 425 |
| 422 libraries.forEach((library) { | 426 libraries.forEach((LibraryEntity library) { |
| 423 library.implementation.forEachLocalMember((element) { | 427 _elementEnvironment.forEachClass(library, (ClassEntity cls) { |
| 424 if (element.isClass) { | 428 String extendsName = _findExtendsNameOfClass(cls); |
| 425 String extendsName = _findExtendsNameOfClass(element); | 429 if (extendsName != null) { |
| 426 if (extendsName != null) { | 430 Set<ClassEntity> potentialSubclasses = potentialExtends.putIfAbsent( |
| 427 Set<ClassElement> potentialSubclasses = potentialExtends | 431 extendsName, () => new Set<ClassEntity>()); |
| 428 .putIfAbsent(extendsName, () => new Set<ClassElement>()); | 432 potentialSubclasses.add(cls); |
| 429 potentialSubclasses.add(element); | |
| 430 } | |
| 431 } | 433 } |
| 432 }); | 434 }); |
| 433 }); | 435 }); |
| 434 | 436 |
| 435 // Resolve all the native classes and any classes that might extend them in | 437 // Resolve all the native classes and any classes that might extend them in |
| 436 // [potentialExtends], and then check that the properly resolved class is in | 438 // [potentialExtends], and then check that the properly resolved class is in |
| 437 // fact a subclass of a native class. | 439 // fact a subclass of a native class. |
| 438 | 440 |
| 439 ClassElement nativeSuperclassOf(ClassElement classElement) { | 441 ClassEntity nativeSuperclassOf(ClassEntity cls) { |
| 440 if (_nativeBasicData.isNativeClass(classElement)) return classElement; | 442 if (_nativeBasicData.isNativeClass(cls)) return cls; |
| 441 if (classElement.superclass == null) return null; | 443 ClassEntity superclass = _elementEnvironment.getSuperClass(cls); |
| 442 return nativeSuperclassOf(classElement.superclass); | 444 if (superclass == null) return null; |
| 445 return nativeSuperclassOf(superclass); |
| 443 } | 446 } |
| 444 | 447 |
| 445 void walkPotentialSubclasses(ClassElement element) { | 448 void walkPotentialSubclasses(ClassEntity element) { |
| 446 if (nativeClassesAndSubclasses.contains(element)) return; | 449 if (nativeClassesAndSubclasses.contains(element)) return; |
| 447 element.ensureResolved(_resolution); | 450 ClassEntity nativeSuperclass = nativeSuperclassOf(element); |
| 448 ClassElement nativeSuperclass = nativeSuperclassOf(element); | |
| 449 if (nativeSuperclass != null) { | 451 if (nativeSuperclass != null) { |
| 450 nativeClassesAndSubclasses.add(element); | 452 nativeClassesAndSubclasses.add(element); |
| 451 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; | 453 Set<ClassEntity> potentialSubclasses = potentialExtends[element.name]; |
| 452 if (potentialSubclasses != null) { | 454 if (potentialSubclasses != null) { |
| 453 potentialSubclasses.forEach(walkPotentialSubclasses); | 455 potentialSubclasses.forEach(walkPotentialSubclasses); |
| 454 } | 456 } |
| 455 } | 457 } |
| 456 } | 458 } |
| 457 | 459 |
| 458 nativeClasses.forEach(walkPotentialSubclasses); | 460 nativeClasses.forEach(walkPotentialSubclasses); |
| 459 nativeClasses.addAll(nativeClassesAndSubclasses); | 461 nativeClasses.addAll(nativeClassesAndSubclasses); |
| 460 } | 462 } |
| 463 } |
| 464 |
| 465 /// Native class finder that extends [BaseNativeClassFinder] to handle |
| 466 /// unresolved classes encountered during the native classes computation. |
| 467 class ResolutionNativeClassFinder extends BaseNativeClassFinder { |
| 468 final DiagnosticReporter _reporter; |
| 469 final Resolution _resolution; |
| 470 |
| 471 ResolutionNativeClassFinder( |
| 472 this._resolution, |
| 473 this._reporter, |
| 474 ElementEnvironment elementEnvironment, |
| 475 CommonElements commonElements, |
| 476 NativeBasicData nativeBasicData) |
| 477 : super(elementEnvironment, commonElements, nativeBasicData); |
| 478 |
| 479 void _processNativeClass( |
| 480 ClassElement classElement, Set<ClassEntity> nativeClasses) { |
| 481 // Resolve class to ensure the class has valid inheritance info. |
| 482 classElement.ensureResolved(_resolution); |
| 483 super._processNativeClass(classElement, nativeClasses); |
| 484 } |
| 461 | 485 |
| 462 /** | 486 /** |
| 463 * Returns the source string of the class named in the extends clause, or | 487 * Returns the source string of the class named in the extends clause, or |
| 464 * `null` if there is no extends clause. | 488 * `null` if there is no extends clause. |
| 465 */ | 489 */ |
| 466 String _findExtendsNameOfClass(ClassElement classElement) { | 490 String _findExtendsNameOfClass(ClassElement classElement) { |
| 467 if (classElement.isResolved) { | 491 if (classElement.isResolved) { |
| 468 ClassElement superClass = classElement.superclass; | 492 ClassElement superClass = classElement.superclass; |
| 469 while (superClass != null) { | 493 while (superClass != null) { |
| 470 if (!superClass.isUnnamedMixinApplication) { | 494 if (!superClass.isUnnamedMixinApplication) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 | 564 |
| 541 Iterable<ConstantValue> fields = constructedObject.fields.values; | 565 Iterable<ConstantValue> fields = constructedObject.fields.values; |
| 542 // TODO(sra): Better validation of the constant. | 566 // TODO(sra): Better validation of the constant. |
| 543 if (fields.length != 1 || fields.single is! StringConstantValue) { | 567 if (fields.length != 1 || fields.single is! StringConstantValue) { |
| 544 throw new SpannableAssertionFailure( | 568 throw new SpannableAssertionFailure( |
| 545 spannable, 'Annotations needs one string: ${value.toStructuredText()}'); | 569 spannable, 'Annotations needs one string: ${value.toStructuredText()}'); |
| 546 } | 570 } |
| 547 StringConstantValue specStringConstant = fields.single; | 571 StringConstantValue specStringConstant = fields.single; |
| 548 return specStringConstant.toDartString().slowToString(); | 572 return specStringConstant.toDartString().slowToString(); |
| 549 } | 573 } |
| OLD | NEW |