blob: 7a3186a6cf1d6f88342846425ac60cda7fd50a53 [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/source/line_info.dart';
// ignore: implementation_imports
import 'package:analyzer/src/dart/element/member.dart' show ExecutableMember;
import 'package:dartdoc/src/element_type.dart';
import 'package:dartdoc/src/model/attribute.dart';
import 'package:dartdoc/src/model/comment_referable.dart';
import 'package:dartdoc/src/model/kind.dart';
import 'package:dartdoc/src/model/model.dart';
class Method extends ModelElement
with ContainerMember, Inheritable, TypeParameters {
@override
final MethodElement2 element;
Container? _enclosingContainer;
final bool _isInherited;
@override
late final List<TypeParameter> typeParameters;
Method(this.element, super.library, super.packageGraph)
: _isInherited = false {
_calcTypeParameters();
}
Method.inherited(this.element, this._enclosingContainer, super.library,
super.packageGraph,
{ExecutableMember? super.originalMember})
: _isInherited = true {
_calcTypeParameters();
}
Method.providedByExtension(
this.element,
this._enclosingContainer,
super.library,
super.packageGraph, {
ExecutableMember? super.originalMember,
}) : _isInherited = false {
_calcTypeParameters();
}
void _calcTypeParameters() {
typeParameters = element.typeParameters2.map((f) {
return getModelFor(f, library) as TypeParameter;
}).toList(growable: false);
}
@override
CharacterLocation? get characterLocation {
if (enclosingElement is Enum && name == 'toString') {
// The toString() method on Enums is special, treated as not having
// a definition location by the analyzer yet not being inherited, either.
// Just directly override our location with the Enum definition --
// this is OK because Enums can not inherit from each other nor
// have their definitions split between files.
return enclosingElement.characterLocation;
}
return super.characterLocation;
}
@override
Container get enclosingElement => _enclosingContainer ??=
getModelFor(element.enclosingElement2!, library) as Container;
@override
String get aboveSidebarPath => enclosingElement.sidebarPath;
@override
String? get belowSidebarPath => null;
String get fullkind {
// A method cannot be abstract and static at the same time.
if (element.isAbstract) return 'abstract $kind';
if (element.isStatic) return 'static $kind';
return kind.toString();
}
@override
String? get href {
assert(!identical(canonicalModelElement, this) ||
canonicalEnclosingContainer == enclosingElement);
return super.href;
}
@override
bool get isInherited => _isInherited;
bool get isOperator => false;
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 => {
...super.attributes,
if (isInherited) Attribute.inherited,
};
bool get isStatic => element.isStatic;
@override
Kind get kind => Kind.method;
@override
ExecutableMember? get originalMember =>
super.originalMember as ExecutableMember?;
late final Callable modelType =
getTypeFor((originalMember ?? element).type, library) as Callable;
@override
Method? get overriddenElement {
if (_enclosingContainer is Extension ||
element.enclosingElement2 is ExtensionElement2) {
return null;
}
var parent = element.enclosingElement2 as InterfaceElement2;
for (var t in parent.allSupertypes) {
Element2? e = t.getMethod2(element.name3 ?? '');
if (e != null) {
assert(
e.enclosingElement2 is InterfaceElement2,
'Expected "${e.enclosingElement2?.name3}" to be a InterfaceElement, '
'but was ${e.enclosingElement2.runtimeType}',
);
return getModelForElement(e) as Method?;
}
}
return null;
}
/// Methods can not be covariant; always returns false.
@override
bool get isCovariant => false;
Map<String, CommentReferable>? _referenceChildren;
@override
Map<String, CommentReferable> get referenceChildren {
var from = documentationFrom.first as Method;
if (!identical(this, from)) {
return from.referenceChildren;
}
return _referenceChildren ??= <String, CommentReferable>{
// If we want to include all types referred to in the signature of this
// method, this is woefully incomplete. Notice we don't currently include
// the element of the returned type itself, nor nested type arguments,
// nor other nested types e.g. in the case of function types or record
// types. But this is all being replaced with analyzer's resolution soon.
...modelType.returnType.typeArguments.modelElements
.explicitOnCollisionWith(this),
...parameters.explicitOnCollisionWith(this),
...typeParameters.explicitOnCollisionWith(this),
};
}
}
extension on Iterable<ElementType> {
/// The [ModelElement] associated with each type, for each type that is a
/// [DefinedElementType].
List<ModelElement> get modelElements => [
for (var type in this)
if (type is DefinedElementType) type.modelElement,
];
}