|
| 1 | +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file |
| 2 | +// for details. All rights reserved. Use of this source code is governed by a |
| 3 | +// BSD-style license that can be found in the LICENSE file. |
| 4 | + |
| 5 | +import 'package:analyzer/dart/element/element.dart'; |
| 6 | +import 'package:dartdoc/src/element_type.dart'; |
| 7 | +import 'package:dartdoc/src/model/feature.dart'; |
| 8 | +import 'package:dartdoc/src/model/getter_setter_combo.dart'; |
| 9 | +import 'package:dartdoc/src/model/library.dart'; |
| 10 | +import 'package:dartdoc/src/model/model_element.dart'; |
| 11 | +import 'package:dartdoc/src/model/package_graph.dart'; |
| 12 | + |
| 13 | +/// Represents a Dart annotation, attached to an element in the source code with |
| 14 | +/// `@`. |
| 15 | +class Annotation extends Feature { |
| 16 | + final ElementAnnotation annotation; |
| 17 | + final Library library; |
| 18 | + final PackageGraph packageGraph; |
| 19 | + |
| 20 | + Annotation(this.annotation, this.library, this.packageGraph) |
| 21 | + : super(annotation.element.name); |
| 22 | + |
| 23 | + String _linkedNameWithParameters; |
| 24 | + @override |
| 25 | + String get linkedNameWithParameters => _linkedNameWithParameters ??= |
| 26 | + packageGraph.rendererFactory.featureRenderer.renderAnnotation(this); |
| 27 | + |
| 28 | + /// Return the linked name of the annotation. |
| 29 | + @override |
| 30 | + String get linkedName => annotation.element is PropertyAccessorElement |
| 31 | + ? ModelElement.fromElement(annotation.element, packageGraph).linkedName |
| 32 | + // TODO(jcollins-g): consider linking to constructor instead of type? |
| 33 | + : modelType.linkedName; |
| 34 | + |
| 35 | + ElementType _modelType; |
| 36 | + ElementType get modelType { |
| 37 | + if (_modelType == null) { |
| 38 | + var annotatedWith = annotation.element; |
| 39 | + if (annotatedWith is ConstructorElement) { |
| 40 | + _modelType = |
| 41 | + ElementType.from(annotatedWith.returnType, library, packageGraph); |
| 42 | + } else if (annotatedWith is PropertyAccessorElement) { |
| 43 | + _modelType = |
| 44 | + (ModelElement.fromElement(annotatedWith.variable, packageGraph) |
| 45 | + as GetterSetterCombo) |
| 46 | + .modelType; |
| 47 | + } else { |
| 48 | + assert(false, |
| 49 | + 'non-callable element used as annotation?: ${annotation.element}'); |
| 50 | + } |
| 51 | + } |
| 52 | + return _modelType; |
| 53 | + } |
| 54 | + |
| 55 | + String _parameterText; |
| 56 | + String get parameterText { |
| 57 | + // TODO(srawlins): Attempt to revive constructor arguments in an annotation, |
| 58 | + // akin to source_gen's Reviver, in order to link to inner components. For |
| 59 | + // example, in `@Foo(const Bar(), baz: <Baz>[Baz.one, Baz.two])`, link to |
| 60 | + // `Foo`, `Bar`, `Baz`, `Baz.one`, and `Baz.two`. |
| 61 | + if (_parameterText == null) { |
| 62 | + var source = annotation.toSource(); |
| 63 | + var startIndex = source.indexOf('('); |
| 64 | + _parameterText = |
| 65 | + source.substring(startIndex == -1 ? source.length : startIndex); |
| 66 | + } |
| 67 | + return _parameterText; |
| 68 | + } |
| 69 | + |
| 70 | + @override |
| 71 | + bool get isPublic => |
| 72 | + modelType.isPublic && |
| 73 | + modelType is DefinedElementType && |
| 74 | + !packageGraph.invisibleAnnotations |
| 75 | + .contains((modelType as DefinedElementType).element); |
| 76 | + |
| 77 | + @override |
| 78 | + bool operator ==(Object other) { |
| 79 | + if (other is Annotation) { |
| 80 | + return other.annotation == annotation; |
| 81 | + } |
| 82 | + return false; |
| 83 | + } |
| 84 | + |
| 85 | + @override |
| 86 | + int get hashCode => annotation.hashCode; |
| 87 | +} |
0 commit comments