| // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/dart/element/type.dart'; |
| import 'package:analyzer/src/dart/element/generic_inferrer.dart'; |
| import 'package:analyzer/src/dart/element/type_algebra.dart'; |
| import 'package:analyzer/src/dart/element/type_system.dart'; |
| |
| extension ClassElementExtensions on ClassElement { |
| /// Return `true` if this element represents the class `Iterable` from |
| /// `dart:core`. |
| bool get isDartCoreIterable => name == 'Iterable' && library.isDartCore; |
| |
| /// Return `true` if this element represents the class `List` from |
| /// `dart:core`. |
| bool get isDartCoreList => name == 'List' && library.isDartCore; |
| |
| /// Return `true` if this element represents the class `Map` from |
| /// `dart:core`. |
| bool get isDartCoreMap => name == 'Map' && library.isDartCore; |
| |
| /// Return `true` if this element represents the class `Set` from |
| /// `dart:core`. |
| bool get isDartCoreSet => name == 'Set' && library.isDartCore; |
| } |
| |
| extension ElementExtension on Element { |
| /// Return `true` if this element, the enclosing class (if there is one), or |
| /// the enclosing library, has been annotated with the `@deprecated` |
| /// annotation. |
| bool get hasOrInheritsDeprecated { |
| if (hasDeprecated) { |
| return true; |
| } |
| var ancestor = enclosingElement; |
| if (ancestor is ClassElement) { |
| if (ancestor.hasDeprecated) { |
| return true; |
| } |
| ancestor = ancestor.enclosingElement; |
| } |
| return ancestor is CompilationUnitElement && |
| ancestor.enclosingElement.hasDeprecated; |
| } |
| |
| /// Return this element and all its enclosing elements. |
| Iterable<Element> get withAncestors sync* { |
| var current = this; |
| while (true) { |
| yield current; |
| var enclosing = current.enclosingElement; |
| if (enclosing == null) { |
| break; |
| } |
| current = enclosing; |
| } |
| } |
| } |
| |
| extension ExtensionElementExtensions on ExtensionElement { |
| /// Use the [type] of the object being extended in the [library] to compute |
| /// the actual type extended by this [extension]. Return the computed type, |
| /// or `null` if the type can't be computed. |
| DartType? resolvedExtendedType(LibraryElement library, DartType type) { |
| final typeParameters = this.typeParameters; |
| var inferrer = |
| GenericInferrer(library.typeSystem as TypeSystemImpl, typeParameters); |
| inferrer.constrainArgument( |
| type, |
| extendedType, |
| 'extendedType', |
| ); |
| var typeArguments = inferrer.infer(typeParameters, |
| failAtError: true, genericMetadataIsEnabled: true); |
| if (typeArguments == null) { |
| return null; |
| } |
| var substitution = Substitution.fromPairs( |
| typeParameters, |
| typeArguments, |
| ); |
| return substitution.substituteType( |
| extendedType, |
| ); |
| } |
| } |
| |
| extension LibraryElementExtensions on LibraryElement { |
| /// Return the extensions in this library that can be applied, within the |
| /// [containingLibrary], to the [targetType] and that define a member with the |
| /// given [memberName]. |
| Iterable<ExtensionElement> matchingExtensionsWithMember( |
| LibraryElement containingLibrary, |
| DartType targetType, |
| String memberName) sync* { |
| for (var unit in units) { |
| for (var extension in unit.extensions) { |
| var extensionName = extension.name; |
| if (extensionName != null && !Identifier.isPrivateName(extensionName)) { |
| var extendedType = |
| extension.resolvedExtendedType(containingLibrary, targetType); |
| if (extendedType != null && |
| typeSystem.isSubtypeOf(targetType, extendedType)) { |
| yield extension; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| extension MethodElementExtensions on MethodElement { |
| /// Return `true` if this element represents the method `cast` from either |
| /// `Iterable`, `List`, `Map`, or `Set`. |
| bool get isCastMethod { |
| if (name != 'cast') { |
| return false; |
| } |
| var definingClass = enclosingElement; |
| if (definingClass is! ClassElement) { |
| return false; |
| } |
| return definingClass.isDartCoreIterable || |
| definingClass.isDartCoreList || |
| definingClass.isDartCoreMap || |
| definingClass.isDartCoreSet; |
| } |
| |
| /// Return `true` if this element represents the method `toList` from either |
| /// `Iterable` or `List`. |
| bool get isToListMethod { |
| if (name != 'toList') { |
| return false; |
| } |
| var definingClass = enclosingElement; |
| if (definingClass is! ClassElement) { |
| return false; |
| } |
| return definingClass.isDartCoreIterable || definingClass.isDartCoreList; |
| } |
| } |