blob: df3207af5b0a5e6a7154be254413cd8d47135114 [file] [log] [blame]
// 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';
}