Chromium Code Reviews| 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 /// Interface for computing all native classes in a set of libraries. |
|
Siggi Cherem (dart-lang)
2017/04/25 19:45:53
nit:
" Interface for computing ..."
=>
" Deter
Johnni Winther
2017/04/26 07:40:19
Done.
| |
| 349 abstract class NativeClassResolver { | 348 abstract class NativeClassResolver { |
| 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 NativeClassResolverImpl implements NativeClassResolver { |
| 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 NativeClassResolverImpl( |
| 359 this._elementEnvironment, this._commonElements, this._nativeBasicData); | |
| 360 | 360 |
| 361 NativeClassResolverImpl(this._resolution, this._reporter, | 361 Iterable<ClassEntity> computeNativeClasses( |
| 362 this._commonElements, this._nativeBasicData); | 362 Iterable<LibraryEntity> libraries) { |
| 363 | 363 Set<ClassEntity> nativeClasses = new Set<ClassEntity>(); |
| 364 Iterable<ClassElement> computeNativeClasses( | |
| 365 Iterable<LibraryElement> libraries) { | |
| 366 Set<ClassElement> nativeClasses = new Set<ClassElement>(); | |
| 367 libraries.forEach((l) => _processNativeClassesInLibrary(l, nativeClasses)); | 364 libraries.forEach((l) => _processNativeClassesInLibrary(l, nativeClasses)); |
| 368 if (_commonElements.isolateHelperLibrary != null) { | 365 if (_commonElements.isolateHelperLibrary != null) { |
| 369 _processNativeClassesInLibrary( | 366 _processNativeClassesInLibrary( |
| 370 _commonElements.isolateHelperLibrary, nativeClasses); | 367 _commonElements.isolateHelperLibrary, nativeClasses); |
| 371 } | 368 } |
| 372 _processSubclassesOfNativeClasses(libraries, nativeClasses); | 369 _processSubclassesOfNativeClasses(libraries, nativeClasses); |
| 373 return nativeClasses; | 370 return nativeClasses; |
| 374 } | 371 } |
| 375 | 372 |
| 373 /// Adds all directly native classes declared in [library] to [nativeClasses]. | |
| 376 void _processNativeClassesInLibrary( | 374 void _processNativeClassesInLibrary( |
| 377 LibraryElement library, Set<ClassElement> nativeClasses) { | 375 LibraryEntity library, Set<ClassEntity> nativeClasses) { |
| 378 // Use implementation to ensure the inclusion of injected members. | 376 _elementEnvironment.forEachClass(library, (ClassEntity cls) { |
| 379 library.implementation.forEachLocalMember((Element element) { | 377 if (_nativeBasicData.isNativeClass(cls)) { |
| 380 if (element.isClass) { | 378 _processNativeClass(cls, nativeClasses); |
| 381 ClassElement cls = element; | |
| 382 if (_nativeBasicData.isNativeClass(cls)) { | |
| 383 _processNativeClass(element, nativeClasses); | |
| 384 } | |
| 385 } | 379 } |
| 386 }); | 380 }); |
| 387 } | 381 } |
| 388 | 382 |
| 389 void _processNativeClass( | 383 /// Adds [cls] to [nativeClasses] and performs further processing of [cls], |
| 390 ClassElement classElement, Set<ClassElement> nativeClasses) { | 384 /// if necessary. |
| 391 nativeClasses.add(classElement); | 385 void _processNativeClass(ClassEntity cls, Set<ClassEntity> nativeClasses) { |
| 392 // Resolve class to ensure the class has valid inheritance info. | 386 nativeClasses.add(cls); |
| 393 classElement.ensureResolved(_resolution); | |
| 394 // Js Interop interfaces do not have tags. | |
| 395 if (_nativeBasicData.isJsInteropClass(classElement)) return; | |
| 396 // Since we map from dispatch tags to classes, a dispatch tag must be used | |
| 397 // on only one native class. | |
| 398 for (String tag in _nativeBasicData.getNativeTagsOfClass(classElement)) { | |
| 399 ClassElement owner = _tagOwner[tag]; | |
| 400 if (owner != null) { | |
| 401 if (owner != classElement) { | |
| 402 _reporter.internalError( | |
| 403 classElement, "Tag '$tag' already in use by '${owner.name}'"); | |
| 404 } | |
| 405 } else { | |
| 406 _tagOwner[tag] = classElement; | |
| 407 } | |
| 408 } | |
| 409 } | 387 } |
| 410 | 388 |
| 389 /// Returns the name of the super class of [cls] or `null` of [cls] has | |
| 390 /// no explicit superclass. | |
| 391 String _findExtendsNameOfClass(ClassEntity cls) { | |
| 392 return _elementEnvironment.getSuperClass(cls)?.name; | |
| 393 } | |
| 394 | |
| 395 /// Adds all subclasses of [nativeClasses] found in [libraries] to | |
| 396 /// [nativeClasses]. | |
| 411 void _processSubclassesOfNativeClasses( | 397 void _processSubclassesOfNativeClasses( |
| 412 Iterable<LibraryElement> libraries, Set<ClassElement> nativeClasses) { | 398 Iterable<LibraryEntity> libraries, Set<ClassEntity> nativeClasses) { |
| 413 Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>(); | 399 Set<ClassEntity> nativeClassesAndSubclasses = new Set<ClassEntity>(); |
| 414 // Collect potential subclasses, e.g. | 400 // Collect potential subclasses, e.g. |
| 415 // | 401 // |
| 416 // class B extends foo.A {} | 402 // class B extends foo.A {} |
| 417 // | 403 // |
| 418 // String "A" has a potential subclass B. | 404 // String "A" has a potential subclass B. |
| 419 | 405 |
| 420 var potentialExtends = new Map<String, Set<ClassElement>>(); | 406 Map<String, Set<ClassEntity>> potentialExtends = |
| 407 <String, Set<ClassEntity>>{}; | |
| 421 | 408 |
| 422 libraries.forEach((library) { | 409 libraries.forEach((LibraryEntity library) { |
| 423 library.implementation.forEachLocalMember((element) { | 410 _elementEnvironment.forEachClass(library, (ClassEntity cls) { |
| 424 if (element.isClass) { | 411 String extendsName = _findExtendsNameOfClass(cls); |
| 425 String extendsName = _findExtendsNameOfClass(element); | 412 if (extendsName != null) { |
| 426 if (extendsName != null) { | 413 Set<ClassEntity> potentialSubclasses = potentialExtends.putIfAbsent( |
| 427 Set<ClassElement> potentialSubclasses = potentialExtends | 414 extendsName, () => new Set<ClassEntity>()); |
| 428 .putIfAbsent(extendsName, () => new Set<ClassElement>()); | 415 potentialSubclasses.add(cls); |
| 429 potentialSubclasses.add(element); | |
| 430 } | |
| 431 } | 416 } |
| 432 }); | 417 }); |
| 433 }); | 418 }); |
| 434 | 419 |
| 435 // Resolve all the native classes and any classes that might extend them in | 420 // 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 | 421 // [potentialExtends], and then check that the properly resolved class is in |
| 437 // fact a subclass of a native class. | 422 // fact a subclass of a native class. |
| 438 | 423 |
| 439 ClassElement nativeSuperclassOf(ClassElement classElement) { | 424 ClassEntity nativeSuperclassOf(ClassEntity cls) { |
| 440 if (_nativeBasicData.isNativeClass(classElement)) return classElement; | 425 if (_nativeBasicData.isNativeClass(cls)) return cls; |
| 441 if (classElement.superclass == null) return null; | 426 ClassEntity superclass = _elementEnvironment.getSuperClass(cls); |
| 442 return nativeSuperclassOf(classElement.superclass); | 427 if (superclass == null) return null; |
| 428 return nativeSuperclassOf(superclass); | |
| 443 } | 429 } |
| 444 | 430 |
| 445 void walkPotentialSubclasses(ClassElement element) { | 431 void walkPotentialSubclasses(ClassEntity element) { |
| 446 if (nativeClassesAndSubclasses.contains(element)) return; | 432 if (nativeClassesAndSubclasses.contains(element)) return; |
| 447 element.ensureResolved(_resolution); | 433 ClassEntity nativeSuperclass = nativeSuperclassOf(element); |
| 448 ClassElement nativeSuperclass = nativeSuperclassOf(element); | |
| 449 if (nativeSuperclass != null) { | 434 if (nativeSuperclass != null) { |
| 450 nativeClassesAndSubclasses.add(element); | 435 nativeClassesAndSubclasses.add(element); |
| 451 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; | 436 Set<ClassEntity> potentialSubclasses = potentialExtends[element.name]; |
| 452 if (potentialSubclasses != null) { | 437 if (potentialSubclasses != null) { |
| 453 potentialSubclasses.forEach(walkPotentialSubclasses); | 438 potentialSubclasses.forEach(walkPotentialSubclasses); |
| 454 } | 439 } |
| 455 } | 440 } |
| 456 } | 441 } |
| 457 | 442 |
| 458 nativeClasses.forEach(walkPotentialSubclasses); | 443 nativeClasses.forEach(walkPotentialSubclasses); |
| 459 nativeClasses.addAll(nativeClassesAndSubclasses); | 444 nativeClasses.addAll(nativeClassesAndSubclasses); |
| 460 } | 445 } |
| 446 } | |
| 447 | |
| 448 /// Native class resolver that extends [NativeClassResolverImpl] to handle | |
| 449 /// unresolved classes encountered during the native classes computation. | |
| 450 class ResolutionNativeClassResolver extends NativeClassResolverImpl { | |
|
Siggi Cherem (dart-lang)
2017/04/25 19:45:53
I don't mind resolver, but another idea: rename "r
Johnni Winther
2017/04/26 07:40:19
Done.
| |
| 451 final DiagnosticReporter _reporter; | |
| 452 final Resolution _resolution; | |
| 453 | |
| 454 Map<String, ClassElement> _tagOwner = new Map<String, ClassElement>(); | |
| 455 | |
| 456 ResolutionNativeClassResolver( | |
| 457 this._resolution, | |
| 458 this._reporter, | |
| 459 ElementEnvironment elementEnvironment, | |
| 460 CommonElements commonElements, | |
| 461 NativeBasicData nativeBasicData) | |
| 462 : super(elementEnvironment, commonElements, nativeBasicData); | |
| 463 | |
| 464 void _processNativeClass( | |
| 465 ClassElement classElement, Set<ClassEntity> nativeClasses) { | |
| 466 nativeClasses.add(classElement); | |
| 467 // Resolve class to ensure the class has valid inheritance info. | |
| 468 classElement.ensureResolved(_resolution); | |
| 469 // Js Interop interfaces do not have tags. | |
| 470 if (_nativeBasicData.isJsInteropClass(classElement)) return; | |
| 471 // Since we map from dispatch tags to classes, a dispatch tag must be used | |
| 472 // on only one native class. | |
|
Siggi Cherem (dart-lang)
2017/04/25 19:45:53
don't we need this validation with Kernel too?
Johnni Winther
2017/04/26 07:40:19
We do. Moved this to BaseNativeClassFinder._proces
| |
| 473 for (String tag in _nativeBasicData.getNativeTagsOfClass(classElement)) { | |
| 474 ClassElement owner = _tagOwner[tag]; | |
| 475 if (owner != null) { | |
| 476 if (owner != classElement) { | |
| 477 _reporter.internalError( | |
| 478 classElement, "Tag '$tag' already in use by '${owner.name}'"); | |
| 479 } | |
| 480 } else { | |
| 481 _tagOwner[tag] = classElement; | |
| 482 } | |
| 483 } | |
| 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 |