| // Copyright (c) 2019, 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/element/element2.dart'; |
| import 'package:analyzer/dart/element/nullability_suffix.dart'; |
| import 'package:analyzer/dart/element/type.dart'; |
| import 'package:dartdoc/src/element_type.dart'; |
| import 'package:dartdoc/src/model/comment_referable.dart'; |
| import 'package:dartdoc/src/model/kind.dart'; |
| import 'package:dartdoc/src/model/model.dart'; |
| import 'package:dartdoc/src/model_utils.dart'; |
| import 'package:meta/meta.dart'; |
| |
| /// Static extension on a given type, containing methods (including getters, |
| /// setters, operators). |
| class Extension extends Container { |
| @override |
| final ExtensionElement2 element; |
| |
| late final ElementType extendedElement = |
| getTypeFor(element.extendedType, library); |
| |
| Extension(this.element, super.library, super.packageGraph); |
| |
| /// Whether this extension applies to every static type. |
| bool get alwaysApplies { |
| var extendedType = extendedElement.type; |
| if (extendedType is TypeParameterType) extendedType = extendedType.bound; |
| return extendedType is DynamicType || |
| extendedType is VoidType || |
| extendedType.isDartCoreObject; |
| } |
| |
| /// Whether this extension could apply to [container]. |
| /// |
| /// This makes some assumptions in its calculations. For example, all |
| /// [InheritingContainer]s represent [InterfaceElement2]s, so no care is taken |
| /// to consider function types or record types. |
| bool couldApplyTo(InheritingContainer container) { |
| var extendedType = extendedElement.type; |
| if (extendedType is TypeParameterType) { |
| extendedType = extendedType.bound; |
| } |
| if (extendedType is DynamicType || extendedType is VoidType) { |
| return true; |
| } |
| extendedType = library.element.typeSystem.promoteToNonNull(extendedType); |
| var otherType = container.modelType.type; |
| if (otherType is InterfaceType) { |
| otherType = library.element.typeSystem.instantiateInterfaceToBounds2( |
| element: otherType.element3, |
| nullabilitySuffix: NullabilitySuffix.none, |
| ); |
| |
| for (var superType in [otherType, ...otherType.allSupertypes]) { |
| var isSameBaseType = superType.element3 == extendedType.element3; |
| if (isSameBaseType && |
| library.element.typeSystem.isSubtypeOf(extendedType, superType)) { |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| @override |
| Library get enclosingElement => library; |
| |
| @override |
| Kind get kind => Kind.extension; |
| |
| @override |
| List<Field> get availableInstanceFieldsSorted => |
| instanceFields.wherePublic.toList(growable: false)..sort(byName); |
| |
| @override |
| late final List<Method> declaredMethods = element.methods2 |
| .map((e) => getModelFor(e, library, enclosingContainer: this) as Method) |
| .toList(growable: false); |
| |
| @override |
| Iterable<Method> get instanceMethods => |
| declaredMethods.where((m) => !m.isStatic && !m.isOperator); |
| |
| @override |
| late final List<Method> availableInstanceMethodsSorted = [ |
| ...instanceMethods.wherePublic, |
| ]..sort(); |
| |
| @override |
| late final List<Operator> availableInstanceOperatorsSorted = [ |
| ...instanceOperators.wherePublic, |
| ]..sort(); |
| |
| @override |
| String get name => element.name3 == null ? '' : super.name; |
| |
| @override |
| late final List<Field> declaredFields = element.fields2.map((field) { |
| ContainerAccessor? getter, setter; |
| final fieldGetter = field.getter2; |
| if (fieldGetter != null) { |
| getter = ModelElement.for_(fieldGetter, library, packageGraph, |
| enclosingContainer: this) as ContainerAccessor; |
| } |
| final fieldSetter = field.setter2; |
| if (fieldSetter != null) { |
| setter = ModelElement.for_(fieldSetter, library, packageGraph, |
| enclosingContainer: this) as ContainerAccessor; |
| } |
| return getModelForPropertyInducingElement(field, library, |
| getter: getter, setter: setter, enclosingContainer: this) as Field; |
| }).toList(growable: false); |
| |
| @override |
| late final List<TypeParameter> typeParameters = element.typeParameters2 |
| .map((typeParameter) => getModelFor( |
| typeParameter, |
| getModelForElement(typeParameter.enclosingElement2!.library2!) |
| as Library) as TypeParameter) |
| .toList(growable: false); |
| |
| @override |
| late final List<ModelElement> allModelElements = [ |
| ...super.allModelElements, |
| ...typeParameters, |
| ]; |
| |
| @override |
| String get sidebarPath => |
| '${canonicalLibraryOrThrow.dirName}/$name-extension-sidebar.html'; |
| |
| Map<String, CommentReferable>? _referenceChildren; |
| @override |
| Map<String, CommentReferable> get referenceChildren { |
| return _referenceChildren ??= { |
| ...extendedElement.referenceChildren, |
| // Override extendedType entries with local items. |
| ...super.referenceChildren, |
| }; |
| } |
| |
| @override |
| @visibleForOverriding |
| Map<String, CommentReferable> get extraReferenceChildren => const {}; |
| |
| @override |
| String get relationshipsClass => 'clazz-relationships'; |
| } |