| // 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 'dart:convert'; |
| |
| import 'package:analyzer/dart/element/element2.dart'; |
| import 'package:dartdoc/src/model/attribute.dart'; |
| import 'package:dartdoc/src/model/kind.dart'; |
| import 'package:dartdoc/src/model/model.dart'; |
| |
| class Field extends ModelElement |
| with GetterSetterCombo, ContainerMember, Inheritable { |
| |
| @override |
| final FieldElement2 element; |
| |
| @override |
| final ContainerAccessor? getter; |
| |
| @override |
| final ContainerAccessor? setter; |
| |
| @override |
| final bool isInherited; |
| |
| @override |
| final Container enclosingElement; |
| |
| Field( |
| this.element, |
| super.library, |
| super.packageGraph, |
| this.getter, |
| this.setter, |
| ) : |
| isInherited = false, |
| enclosingElement = |
| ModelElement.for_(element.enclosingElement2, library, packageGraph) |
| as Container, |
| assert(getter != null || setter != null) { |
| getter?.enclosingCombo = this; |
| setter?.enclosingCombo = this; |
| } |
| |
| Field.providedByExtension( |
| this.element, |
| this.enclosingElement, |
| super.library, |
| super.packageGraph, |
| this.getter, |
| this.setter, |
| ) : |
| isInherited = false, |
| assert(getter != null || setter != null) { |
| getter?.enclosingCombo = this; |
| setter?.enclosingCombo = this; |
| } |
| |
| Field.inherited( |
| this.element, |
| this.enclosingElement, |
| super.library, |
| super.packageGraph, |
| this.getter, |
| this.setter, |
| ) : |
| isInherited = true, |
| assert(getter != null || setter != null) { |
| // Can't set `isInherited` to true if this is the defining element, because |
| // that would mean it isn't inherited. |
| assert(enclosingElement != definingEnclosingContainer); |
| getter?.enclosingCombo = this; |
| setter?.enclosingCombo = this; |
| } |
| |
| @override |
| String get documentation { |
| if (enclosingElement is Enum) { |
| if (name == 'values') { |
| return 'A constant List of the values in this enum, in order of their declaration.'; |
| } else if (name == 'index') { |
| return 'The integer index of this enum value.'; |
| } |
| } |
| |
| // Verify that [hasSetter] and [hasGetthasPublicGetterNoSettererNoSetter] |
| // are mutually exclusive, to prevent displaying more or less than one |
| // summary. |
| if (isPublic) { |
| assert((hasPublicSetter && !hasPublicGetterNoSetter) || |
| (!hasPublicSetter && hasPublicGetterNoSetter)); |
| } |
| return super.documentation; |
| } |
| |
| @override |
| String? get href { |
| assert(!identical(canonicalModelElement, this) || |
| canonicalEnclosingContainer == enclosingElement); |
| return super.href; |
| } |
| |
| @override |
| bool get isConst => element.isConst; |
| |
| /// Whether the [FieldElement2] is covariant, or the first parameter for the |
| /// setter is covariant. |
| @override |
| bool get isCovariant => setter?.isCovariant == true || element.isCovariant; |
| |
| /// Whether this field is final. |
| /// |
| /// `Element.isFinal` returns `true` even if it has an explicit getter (which |
| /// means we should not document it as "final"). |
| @override |
| bool get isFinal { |
| if (hasExplicitGetter) return false; |
| return element.isFinal; |
| } |
| |
| @override |
| bool get isLate => isFinal && element.isLate; |
| |
| bool get isStatic => element.isStatic; |
| |
| @override |
| Kind get kind => isConst ? Kind.constant : Kind.property; |
| |
| String get fullkind => |
| element.isAbstract ? 'abstract $kind' : kind.toString(); |
| |
| bool get isProvidedByExtension => |
| element.enclosingElement2 is ExtensionElement2; |
| |
| /// The [enclosingElement], which is expected to be an [Extension]. |
| Extension get enclosingExtension => enclosingElement as Extension; |
| |
| @override |
| Set<Attribute> get attributes { |
| var allAttributes = {...super.attributes, ...comboAttributes}; |
| // Combo attributes can indicate 'inherited' and 'override' if either the |
| // getter or setter has one of those properties, but that's not really |
| // specific enough for [Field]s that have public getter/setters. |
| if (hasPublicGetter && hasPublicSetter) { |
| if (getter!.isInherited && setter!.isInherited) { |
| allAttributes.add(Attribute.inherited); |
| } else { |
| allAttributes.remove(Attribute.inherited); |
| if (getter!.isInherited) allAttributes.add(Attribute.inheritedGetter); |
| if (setter!.isInherited) allAttributes.add(Attribute.inheritedSetter); |
| } |
| if (getter!.isOverride && setter!.isOverride) { |
| allAttributes.add(Attribute.override_); |
| } else { |
| allAttributes.remove(Attribute.override_); |
| if (getter!.isOverride) allAttributes.add(Attribute.overrideGetter); |
| if (setter!.isOverride) allAttributes.add(Attribute.overrideSetter); |
| } |
| } else { |
| if (isInherited) allAttributes.add(Attribute.inherited); |
| if (isOverride) allAttributes.add(Attribute.override_); |
| } |
| return allAttributes; |
| } |
| |
| @override |
| String get fileName => '${isConst ? '$name-constant' : name}.html'; |
| |
| @override |
| String get aboveSidebarPath => enclosingElement.sidebarPath; |
| |
| @override |
| String? get belowSidebarPath => null; |
| |
| late final String _sourceCode = () { |
| // We could use a set to figure the dupes out, but that would lose ordering. |
| var fieldSourceCode = modelNode?.sourceCode ?? ''; |
| var getterSourceCode = getter?.sourceCode ?? ''; |
| var setterSourceCode = setter?.sourceCode ?? ''; |
| var buffer = StringBuffer(); |
| if (fieldSourceCode.isNotEmpty) { |
| fieldSourceCode = const HtmlEscape().convert(fieldSourceCode); |
| buffer.write(fieldSourceCode); |
| } |
| if (buffer.isNotEmpty) buffer.write('\n\n'); |
| if (fieldSourceCode != getterSourceCode) { |
| if (getterSourceCode != setterSourceCode) { |
| buffer.write(getterSourceCode); |
| if (buffer.isNotEmpty) buffer.write('\n\n'); |
| } |
| } |
| if (fieldSourceCode != setterSourceCode) { |
| buffer.write(setterSourceCode); |
| } |
| return buffer.toString().trim(); |
| }(); |
| |
| @override |
| String get sourceCode => _sourceCode; |
| |
| @override |
| Inheritable? get overriddenElement => null; |
| } |