| // 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:analyzer/src/dart/element/member.dart' show Member; |
| import 'package:dartdoc/src/model/model.dart'; |
| import 'package:dartdoc/src/utils.dart'; |
| import 'package:dartdoc/src/warnings.dart'; |
| |
| /// Getters and setters. |
| class Accessor extends ModelElement implements EnclosedElement { |
| GetterSetterCombo enclosingCombo; |
| |
| Accessor(PropertyAccessorElement element, Library library, |
| PackageGraph packageGraph, Member originalMember) |
| : super(element, library, packageGraph, originalMember); |
| |
| String get linkedReturnType { |
| assert(isGetter); |
| return modelType.createLinkedReturnTypeName(); |
| } |
| |
| bool get isSynthetic => element.isSynthetic; |
| |
| GetterSetterCombo _definingCombo; |
| // The [enclosingCombo] where this element was defined. |
| GetterSetterCombo get definingCombo { |
| if (_definingCombo == null) { |
| var variable = (element as PropertyAccessorElement).variable; |
| _definingCombo = ModelElement.fromElement(variable, packageGraph); |
| assert(_definingCombo != null, 'Unable to find defining combo'); |
| } |
| return _definingCombo; |
| } |
| |
| String _sourceCode; |
| |
| @override |
| String get sourceCode { |
| if (_sourceCode == null) { |
| if (isSynthetic) { |
| _sourceCode = |
| packageGraph.getModelNodeFor(definingCombo.element).sourceCode; |
| } else { |
| _sourceCode = super.sourceCode; |
| } |
| } |
| return _sourceCode; |
| } |
| |
| @override |
| String computeDocumentationComment() { |
| if (isSynthetic) { |
| // If we're a setter, only display something if we have something different than the getter. |
| // TODO(jcollins-g): modify analyzer to do this itself? |
| if (isGetter || |
| definingCombo.hasNodoc || |
| (isSetter && |
| definingCombo.hasGetter && |
| definingCombo.getter.documentationComment != |
| definingCombo.documentationComment)) { |
| return stripComments(definingCombo.documentationComment); |
| } else { |
| return ''; |
| } |
| } |
| return stripComments(super.computeDocumentationComment()); |
| } |
| |
| @override |
| void warn(PackageWarning kind, |
| {String message, |
| Iterable<Locatable> referredFrom, |
| Iterable<String> extendedDebug}) { |
| enclosingCombo.warn(kind, |
| message: message, |
| referredFrom: referredFrom, |
| extendedDebug: extendedDebug); |
| } |
| |
| @override |
| ModelElement get enclosingElement { |
| if (_accessor.enclosingElement is CompilationUnitElement) { |
| return packageGraph.findButDoNotCreateLibraryFor( |
| _accessor.enclosingElement.enclosingElement); |
| } |
| |
| return ModelElement.from(_accessor.enclosingElement, library, packageGraph); |
| } |
| |
| @override |
| String get filePath => enclosingCombo.filePath; |
| |
| @override |
| bool get isCanonical => enclosingCombo.isCanonical; |
| |
| @override |
| String get href { |
| return enclosingCombo.href; |
| } |
| |
| bool get isGetter => _accessor.isGetter; |
| |
| bool get isSetter => _accessor.isSetter; |
| |
| @override |
| String get kind => 'accessor'; |
| |
| String _namePart; |
| |
| @override |
| String get namePart { |
| _namePart ??= super.namePart.split('=').first; |
| return _namePart; |
| } |
| |
| PropertyAccessorElement get _accessor => (element as PropertyAccessorElement); |
| } |
| |
| /// A getter or setter that is a member of a [Container]. |
| class ContainerAccessor extends Accessor with ContainerMember, Inheritable { |
| /// Factory will return an [ContainerAccessor] with isInherited = true |
| /// if [element] is in [inheritedAccessors]. |
| factory ContainerAccessor.from(PropertyAccessorElement element, |
| Set<PropertyAccessorElement> inheritedAccessors, Class enclosingClass) { |
| ContainerAccessor accessor; |
| if (element == null) return null; |
| if (inheritedAccessors.contains(element)) { |
| accessor = ModelElement.from( |
| element, enclosingClass.library, enclosingClass.packageGraph, |
| enclosingContainer: enclosingClass); |
| } else { |
| accessor = ModelElement.from( |
| element, enclosingClass.library, enclosingClass.packageGraph); |
| } |
| return accessor; |
| } |
| |
| ModelElement _enclosingElement; |
| bool _isInherited = false; |
| |
| @override |
| bool get isCovariant => isSetter && parameters.first.isCovariant; |
| |
| ContainerAccessor(PropertyAccessorElement element, Library library, |
| PackageGraph packageGraph) |
| : super(element, library, packageGraph, null); |
| |
| ContainerAccessor.inherited(PropertyAccessorElement element, Library library, |
| PackageGraph packageGraph, this._enclosingElement, |
| {Member originalMember}) |
| : super(element, library, packageGraph, originalMember) { |
| _isInherited = true; |
| } |
| |
| @override |
| bool get isInherited => _isInherited; |
| |
| @override |
| Container get enclosingElement { |
| _enclosingElement ??= super.enclosingElement; |
| return _enclosingElement; |
| } |
| |
| bool _overriddenElementIsSet = false; |
| ModelElement _overriddenElement; |
| |
| @override |
| ContainerAccessor get overriddenElement { |
| assert(packageGraph.allLibrariesAdded); |
| if (!_overriddenElementIsSet) { |
| _overriddenElementIsSet = true; |
| var parent = element.enclosingElement; |
| if (parent is ClassElement) { |
| for (var t in parent.allSupertypes) { |
| Element accessor = |
| isGetter ? t.getGetter(element.name) : t.getSetter(element.name); |
| if (accessor != null) { |
| accessor = accessor.declaration; |
| Class parentClass = |
| ModelElement.fromElement(t.element, packageGraph); |
| var possibleFields = <Field>[]; |
| possibleFields.addAll(parentClass.instanceFields); |
| possibleFields.addAll(parentClass.staticFields); |
| var fieldName = accessor.name.replaceFirst('=', ''); |
| var foundField = possibleFields.firstWhere( |
| (f) => f.element.name == fieldName, |
| orElse: () => null); |
| if (foundField != null) { |
| if (isGetter) { |
| _overriddenElement = foundField.getter; |
| } else { |
| _overriddenElement = foundField.setter; |
| } |
| assert(!(_overriddenElement as ContainerAccessor).isInherited); |
| break; |
| } |
| } |
| } |
| } |
| } |
| return _overriddenElement; |
| } |
| } |