| // 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/element.dart'; |
| import 'package:dartdoc/src/model/model.dart'; |
| import 'package:dartdoc/src/model_utils.dart' as model_utils; |
| import 'package:dartdoc/src/quiver.dart' as quiver; |
| import 'package:meta/meta.dart'; |
| |
| /// A [Container] represents a Dart construct that can contain methods, |
| /// operators, and fields, such as [Class], [Enum], or [Extension]. |
| /// |
| /// Member naming in [Container] follows these general rules: |
| /// |
| /// **instance** : Members named 'instance' contain the children of this |
| /// container that can be referenced from within the container without a prefix. |
| /// Usually overridden in subclasses with calls to super. |
| /// **constant** : Members named 'constant' contain children declared constant. |
| /// **variable** : The opposite of constant. For the templating system. |
| /// **static** : Members named 'static' are related to static children of this |
| /// container. |
| /// **public** : Filtered versions of the getters showing only public items. |
| /// Mostly for the templating system. |
| /// **sorted** : Filtered versions of the getters creating a sorted list by |
| /// name. For the templating system. |
| /// **has** : boolean getters indicating whether the underlying getters are |
| /// empty. Mostly for the templating system. |
| /// **all** : Referring to all children. |
| abstract class Container extends ModelElement with TypeParameters { |
| Container(Element element, Library library, PackageGraph packageGraph) |
| : super(element, library, packageGraph, null); |
| |
| bool get isClass => element is ClassElement; |
| bool get isExtension => element is ExtensionElement; |
| |
| @mustCallSuper |
| Iterable<ModelElement> get allModelElements => quiver.concat([ |
| instanceMethods, |
| instanceFields, |
| instanceOperators, |
| instanceAccessors, |
| staticFields, |
| staticAccessors, |
| staticMethods, |
| ]); |
| |
| /// All methods, including operators and statics, declared as part of this |
| /// [Container]. [declaredMethods] must be the union of [instanceMethods], |
| /// [staticMethods], and [instanceOperators]. |
| Iterable<Method> get declaredMethods; |
| |
| Iterable<Method> get instanceMethods => declaredMethods |
| .where((m) => !m.isStatic && !m.isOperator) |
| .toList(growable: false); |
| |
| /// Whether any constructors are public. |
| /// |
| /// This is only used in mustache templates. |
| bool get hasPublicConstructors => false; |
| |
| Iterable<Constructor> get publicConstructorsSorted => []; |
| |
| /// Whether all instance fields are inherited. |
| /// |
| /// This is only used in mustache templates. |
| bool get publicInheritedInstanceFields => false; |
| |
| /// Whether all instance methods are inherited. |
| /// |
| /// This is only used in mustache templates. |
| bool get publicInheritedInstanceMethods => false; |
| |
| Iterable<Operator> get publicInheritedInstanceOperators => []; |
| |
| @nonVirtual |
| bool get hasPublicInstanceMethods => |
| model_utils.filterNonPublic(instanceMethods).isNotEmpty; |
| |
| Iterable<Method> get publicInstanceMethods => |
| model_utils.filterNonPublic(instanceMethods); |
| |
| List<Method> _publicInstanceMethodsSorted; |
| List<Method> get publicInstanceMethodsSorted => |
| _publicInstanceMethodsSorted ?? publicInstanceMethods.toList() |
| ..sort(byName); |
| |
| Iterable<Operator> _declaredOperators; |
| @nonVirtual |
| Iterable<Operator> get declaredOperators { |
| _declaredOperators ??= |
| declaredMethods.whereType<Operator>().toList(growable: false); |
| return _declaredOperators; |
| } |
| |
| Iterable<Operator> get instanceOperators => declaredOperators; |
| |
| @nonVirtual |
| bool get hasPublicInstanceOperators => |
| publicInstanceOperatorsSorted.isNotEmpty; |
| |
| @nonVirtual |
| Iterable<Operator> get publicInstanceOperators => |
| model_utils.filterNonPublic(instanceOperators); |
| |
| List<Operator> _publicInstanceOperatorsSorted; |
| List<Operator> get publicInstanceOperatorsSorted => |
| _publicInstanceOperatorsSorted ??= publicInstanceOperators.toList() |
| ..sort(byName); |
| |
| /// Fields fully declared in this [Container]. |
| Iterable<Field> get declaredFields; |
| |
| /// All fields accessible in this instance that are not static. |
| Iterable<Field> get instanceFields => |
| declaredFields.where((f) => !f.isStatic); |
| |
| bool get hasInstanceFields => instanceFields.isNotEmpty; |
| |
| @nonVirtual |
| Iterable<Field> get publicInstanceFields => |
| model_utils.filterNonPublic(instanceFields); |
| |
| @nonVirtual |
| bool get hasPublicInstanceFields => publicInstanceFields.isNotEmpty; |
| |
| List<Field> _publicInstanceFieldsSorted; |
| List<Field> get publicInstanceFieldsSorted => _publicInstanceFieldsSorted ??= |
| publicInstanceFields.toList()..sort(byName); |
| |
| Iterable<Field> get constantFields => declaredFields.where((f) => f.isConst); |
| |
| Iterable<Field> get publicConstantFields => |
| model_utils.filterNonPublic(constantFields); |
| |
| bool get hasPublicConstantFields => publicConstantFieldsSorted.isNotEmpty; |
| |
| List<Field> _publicConstantFieldsSorted; |
| List<Field> get publicConstantFieldsSorted => _publicConstantFieldsSorted ??= |
| publicConstantFields.toList()..sort(byName); |
| |
| Iterable<Accessor> get instanceAccessors => |
| instanceFields.expand((f) => f.allAccessors); |
| |
| Iterable<Accessor> get staticAccessors => |
| staticFields.expand((f) => f.allAccessors); |
| |
| /// This container might be canonical for elements it does not contain. |
| /// See [Inheritable.canonicalEnclosingContainer]. |
| bool containsElement(Element element) => allElements.contains(element); |
| |
| Set<Element> _allElements; |
| Set<Element> get allElements => |
| _allElements ??= allModelElements.map((e) => e.element).toSet(); |
| |
| Map<String, List<ModelElement>> _membersByName; |
| |
| /// Given a ModelElement that is a member of some other class, return |
| /// the member of this class that has the same name and runtime type. |
| /// |
| /// This enables object substitution for canonicalization, such as Interceptor |
| /// for Object. |
| T memberByExample<T extends ModelElement>(T example) { |
| if (_membersByName == null) { |
| _membersByName = {}; |
| for (var me in allModelElements) { |
| if (!_membersByName.containsKey(me.name)) { |
| _membersByName[me.name] = []; |
| } |
| _membersByName[me.name].add(me); |
| } |
| } |
| ModelElement member; |
| // [T] is insufficiently specific to disambiguate between different |
| // subtypes of [Inheritable] or other mixins/implementations of |
| // [ModelElement] via [Iterable.whereType]. |
| var possibleMembers = _membersByName[example.name] |
| .where((e) => e.runtimeType == example.runtimeType); |
| if (example is Accessor) { |
| possibleMembers = possibleMembers |
| .where((e) => example.isGetter == (e as Accessor).isGetter); |
| } |
| member = possibleMembers.first; |
| assert(possibleMembers.length == 1); |
| return member; |
| } |
| |
| Map<String, List<ModelElement>> _allModelElementsByNamePart; |
| |
| /// Helper for `_MarkdownCommentReference._getResultsForClass`. |
| Map<String, List<ModelElement>> get allModelElementsByNamePart { |
| if (_allModelElementsByNamePart == null) { |
| _allModelElementsByNamePart = {}; |
| for (var me in allModelElements) { |
| _allModelElementsByNamePart.update( |
| me.namePart, (List<ModelElement> v) => v..add(me), |
| ifAbsent: () => <ModelElement>[me]); |
| } |
| } |
| return _allModelElementsByNamePart; |
| } |
| |
| bool get hasPublicStaticFields => publicStaticFieldsSorted.isNotEmpty; |
| |
| Iterable<Field> get publicStaticFields => |
| model_utils.filterNonPublic(staticFields); |
| |
| List<Field> _publicStaticFieldsSorted; |
| List<Field> get publicStaticFieldsSorted => |
| _publicStaticFieldsSorted ??= publicStaticFields.toList()..sort(byName); |
| |
| Iterable<Field> get staticFields => declaredFields.where((f) => f.isStatic); |
| |
| Iterable<Field> get variableStaticFields => |
| staticFields.where((f) => !f.isConst); |
| |
| bool get hasPublicVariableStaticFields => |
| publicVariableStaticFieldsSorted.isNotEmpty; |
| |
| Iterable<Field> get publicVariableStaticFields => |
| model_utils.filterNonPublic(variableStaticFields); |
| |
| List<Field> _publicVariableStaticFieldsSorted; |
| List<Field> get publicVariableStaticFieldsSorted => |
| _publicVariableStaticFieldsSorted ??= publicVariableStaticFields.toList() |
| ..sort(byName); |
| |
| Iterable<Method> get staticMethods => |
| declaredMethods.where((m) => m.isStatic); |
| |
| bool get hasPublicStaticMethods => |
| model_utils.filterNonPublic(publicStaticMethodsSorted).isNotEmpty; |
| |
| Iterable<Method> get publicStaticMethods => |
| model_utils.filterNonPublic(staticMethods); |
| |
| List<Method> _publicStaticMethodsSorted; |
| List<Method> get publicStaticMethodsSorted => |
| _publicStaticMethodsSorted ??= publicStaticMethods.toList()..sort(byName); |
| } |