| Index: pkg/analysis_server/lib/src/computer/computer_overrides.dart
|
| diff --git a/pkg/analysis_server/lib/src/computer/computer_overrides.dart b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
|
| index 8a742125b21e28845847ea3b577d685899296f28..4eb93d1bf22a0d97fcfbd1c2a0576a02f9c2dbae 100644
|
| --- a/pkg/analysis_server/lib/src/computer/computer_overrides.dart
|
| +++ b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
|
| @@ -5,65 +5,42 @@
|
| library computer.overrides;
|
|
|
| import 'package:analysis_server/src/collections.dart';
|
| -import 'package:analysis_server/src/protocol_server.dart';
|
| -import 'package:analyzer/dart/element/element.dart' as engine;
|
| -import 'package:analyzer/dart/element/type.dart' as engine;
|
| +import 'package:analysis_server/src/protocol_server.dart' as proto;
|
| +import 'package:analyzer/dart/element/element.dart';
|
| +import 'package:analyzer/dart/element/type.dart';
|
| import 'package:analyzer/src/generated/ast.dart';
|
|
|
| /**
|
| + * Return the elements that the given [element] overrides.
|
| + */
|
| +OverriddenElements findOverriddenElements(Element element) {
|
| + if (element?.enclosingElement is ClassElement) {
|
| + return new _OverriddenElementsFinder(element).find();
|
| + }
|
| + return new OverriddenElements(element, <Element>[], <Element>[]);
|
| +}
|
| +
|
| +/**
|
| * A computer for class member overrides in a Dart [CompilationUnit].
|
| */
|
| class DartUnitOverridesComputer {
|
| - static const List<ElementKind> FIELD_KINDS = const <ElementKind>[
|
| - ElementKind.FIELD,
|
| - ElementKind.GETTER,
|
| - ElementKind.SETTER
|
| - ];
|
| -
|
| - static const List<ElementKind> GETTER_KINDS = const <ElementKind>[
|
| - ElementKind.FIELD,
|
| - ElementKind.GETTER
|
| - ];
|
| -
|
| - static const List<ElementKind> METHOD_KINDS = const <ElementKind>[
|
| - ElementKind.METHOD
|
| - ];
|
| -
|
| - static const List<ElementKind> SETTER_KINDS = const <ElementKind>[
|
| - ElementKind.FIELD,
|
| - ElementKind.SETTER
|
| - ];
|
| -
|
| final CompilationUnit _unit;
|
| -
|
| - final List<Override> _overrides = <Override>[];
|
| - engine.ClassElement _currentClass;
|
| + final List<proto.Override> _overrides = <proto.Override>[];
|
|
|
| DartUnitOverridesComputer(this._unit);
|
|
|
| /**
|
| * Returns the computed occurrences, not `null`.
|
| */
|
| - List<Override> compute() {
|
| + List<proto.Override> compute() {
|
| for (CompilationUnitMember unitMember in _unit.declarations) {
|
| if (unitMember is ClassDeclaration) {
|
| - _currentClass = unitMember.element;
|
| for (ClassMember classMember in unitMember.members) {
|
| if (classMember is MethodDeclaration) {
|
| if (classMember.isStatic) {
|
| continue;
|
| }
|
| - SimpleIdentifier name = classMember.name;
|
| - List<ElementKind> kinds;
|
| - if (classMember.isGetter) {
|
| - kinds = GETTER_KINDS;
|
| - } else if (classMember.isSetter) {
|
| - kinds = SETTER_KINDS;
|
| - } else {
|
| - kinds = METHOD_KINDS;
|
| - }
|
| - new _SingleOverrideComputer(_currentClass, name, kinds)
|
| - .addOverrideTo(_overrides);
|
| + _addOverride(classMember.name);
|
| }
|
| if (classMember is FieldDeclaration) {
|
| if (classMember.isStatic) {
|
| @@ -71,9 +48,7 @@ class DartUnitOverridesComputer {
|
| }
|
| List<VariableDeclaration> fields = classMember.fields.variables;
|
| for (VariableDeclaration field in fields) {
|
| - SimpleIdentifier name = field.name;
|
| - new _SingleOverrideComputer(_currentClass, name, FIELD_KINDS)
|
| - .addOverrideTo(_overrides);
|
| + _addOverride(field.name);
|
| }
|
| }
|
| }
|
| @@ -81,105 +56,171 @@ class DartUnitOverridesComputer {
|
| }
|
| return _overrides;
|
| }
|
| -}
|
| -
|
| -/**
|
| - * Computer for [Override] for a single declaration.
|
| - */
|
| -class _SingleOverrideComputer {
|
| - final engine.LibraryElement currentLibrary;
|
| - final engine.ClassElement currentClass;
|
| - final SimpleIdentifier node;
|
| - final String name;
|
| - final List<ElementKind> kinds;
|
| -
|
| - _SingleOverrideComputer(
|
| - engine.ClassElement currentClass, SimpleIdentifier node, this.kinds)
|
| - : currentClass = currentClass,
|
| - currentLibrary = currentClass.library,
|
| - node = node,
|
| - name = node.name;
|
|
|
| /**
|
| - * Add a new [Override] for this declaration to the given [overrides].
|
| + * Add a new [Override] for the declaration with the given name [node].
|
| */
|
| - void addOverrideTo(List<Override> overrides) {
|
| - // super
|
| - engine.Element superEngineElement;
|
| - {
|
| - engine.InterfaceType superType = currentClass.supertype;
|
| - if (superType != null) {
|
| - superEngineElement = _lookupMember(superType.element);
|
| - }
|
| - }
|
| - // interfaces
|
| - Set<engine.Element> interfaceEngineElements = new Set<engine.Element>();
|
| - _addInterfaceOverrides(interfaceEngineElements, currentClass.type, false,
|
| - new Set<engine.InterfaceType>());
|
| - interfaceEngineElements.remove(superEngineElement);
|
| - // is there any override?
|
| - if (superEngineElement != null || interfaceEngineElements.isNotEmpty) {
|
| - OverriddenMember superMember = superEngineElement != null
|
| - ? newOverriddenMember_fromEngine(superEngineElement)
|
| + void _addOverride(SimpleIdentifier node) {
|
| + Element element = node.staticElement;
|
| + OverriddenElements overridesResult =
|
| + new _OverriddenElementsFinder(element).find();
|
| + List<Element> superElements = overridesResult.superElements;
|
| + List<Element> interfaceElements = overridesResult.interfaceElements;
|
| + if (superElements.isNotEmpty || interfaceElements.isNotEmpty) {
|
| + proto.OverriddenMember superMember = superElements.isNotEmpty
|
| + ? proto.newOverriddenMember_fromEngine(superElements.first)
|
| : null;
|
| - List<OverriddenMember> interfaceMembers = interfaceEngineElements
|
| - .map((member) => newOverriddenMember_fromEngine(member))
|
| + List<proto.OverriddenMember> interfaceMembers = interfaceElements
|
| + .map((member) => proto.newOverriddenMember_fromEngine(member))
|
| .toList();
|
| - overrides.add(new Override(node.offset, node.length,
|
| + _overrides.add(new proto.Override(node.offset, node.length,
|
| superclassMember: superMember,
|
| interfaceMembers: nullIfEmpty(interfaceMembers)));
|
| }
|
| }
|
| +}
|
|
|
| - void _addInterfaceOverrides(
|
| - Set<engine.Element> elements,
|
| - engine.InterfaceType type,
|
| - bool checkType,
|
| - Set<engine.InterfaceType> visited) {
|
| +/**
|
| + * The container with elements that a class member overrides.
|
| + */
|
| +class OverriddenElements {
|
| + /**
|
| + * The element that overrides other class members.
|
| + */
|
| + final Element element;
|
| +
|
| + /**
|
| + * The elements that [element] overrides and which is defined in a class that
|
| + * is a superclass of the class that defines [element].
|
| + */
|
| + final List<Element> superElements;
|
| +
|
| + /**
|
| + * The elements that [element] overrides and which is defined in a class that
|
| + * which is implemented by the class that defines [element].
|
| + */
|
| + final List<Element> interfaceElements;
|
| +
|
| + OverriddenElements(this.element, this.superElements, this.interfaceElements);
|
| +}
|
| +
|
| +class _OverriddenElementsFinder {
|
| + static const List<ElementKind> FIELD_KINDS = const <ElementKind>[
|
| + ElementKind.FIELD,
|
| + ElementKind.GETTER,
|
| + ElementKind.SETTER
|
| + ];
|
| +
|
| + static const List<ElementKind> GETTER_KINDS = const <ElementKind>[
|
| + ElementKind.FIELD,
|
| + ElementKind.GETTER
|
| + ];
|
| +
|
| + static const List<ElementKind> METHOD_KINDS = const <ElementKind>[
|
| + ElementKind.METHOD
|
| + ];
|
| +
|
| + static const List<ElementKind> SETTER_KINDS = const <ElementKind>[
|
| + ElementKind.FIELD,
|
| + ElementKind.SETTER
|
| + ];
|
| +
|
| + Element _seed;
|
| + LibraryElement _library;
|
| + ClassElement _class;
|
| + String _name;
|
| + List<ElementKind> _kinds;
|
| +
|
| + List<Element> _superElements = <Element>[];
|
| + List<Element> _interfaceElements = <Element>[];
|
| + Set<InterfaceType> _visited = new Set<InterfaceType>();
|
| +
|
| + _OverriddenElementsFinder(Element seed) {
|
| + _seed = seed;
|
| + _class = seed.enclosingElement;
|
| + _library = _class.library;
|
| + _name = seed.displayName;
|
| + if (seed is MethodElement) {
|
| + _kinds = METHOD_KINDS;
|
| + } else if (seed is PropertyAccessorElement) {
|
| + _kinds = seed.isGetter ? GETTER_KINDS : SETTER_KINDS;
|
| + } else {
|
| + _kinds = FIELD_KINDS;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Add the [OverriddenElements] for this element.
|
| + */
|
| + OverriddenElements find() {
|
| + _visited.clear();
|
| + _addSuperOverrides(_class.supertype);
|
| + _visited.clear();
|
| + _addInterfaceOverrides(_class.type, false);
|
| + _superElements.forEach(_interfaceElements.remove);
|
| + return new OverriddenElements(_seed, _superElements, _interfaceElements);
|
| + }
|
| +
|
| + void _addInterfaceOverrides(InterfaceType type, bool checkType) {
|
| if (type == null) {
|
| return;
|
| }
|
| - if (!visited.add(type)) {
|
| + if (!_visited.add(type)) {
|
| return;
|
| }
|
| - // check type
|
| + // this type
|
| if (checkType) {
|
| - engine.Element element = _lookupMember(type.element);
|
| - if (element != null) {
|
| - elements.add(element);
|
| - return;
|
| + Element element = _lookupMember(type.element);
|
| + if (element != null && !_interfaceElements.contains(element)) {
|
| + _interfaceElements.add(element);
|
| }
|
| }
|
| - // check interfaces
|
| - for (engine.InterfaceType interfaceType in type.interfaces) {
|
| - _addInterfaceOverrides(elements, interfaceType, true, visited);
|
| + // interfaces
|
| + for (InterfaceType interfaceType in type.interfaces) {
|
| + _addInterfaceOverrides(interfaceType, true);
|
| }
|
| - // check super
|
| - _addInterfaceOverrides(elements, type.superclass, checkType, visited);
|
| + // super
|
| + _addInterfaceOverrides(type.superclass, checkType);
|
| + }
|
| +
|
| + void _addSuperOverrides(InterfaceType type) {
|
| + if (type == null) {
|
| + return;
|
| + }
|
| + if (!_visited.add(type)) {
|
| + return;
|
| + }
|
| + // this type
|
| + Element element = _lookupMember(type.element);
|
| + if (element != null && !_superElements.contains(element)) {
|
| + _superElements.add(element);
|
| + }
|
| + // super
|
| + _addSuperOverrides(type.superclass);
|
| }
|
|
|
| - engine.Element _lookupMember(engine.ClassElement classElement) {
|
| + Element _lookupMember(ClassElement classElement) {
|
| if (classElement == null) {
|
| return null;
|
| }
|
| - engine.Element member;
|
| + Element member;
|
| // method
|
| - if (kinds.contains(ElementKind.METHOD)) {
|
| - member = classElement.lookUpMethod(name, currentLibrary);
|
| + if (_kinds.contains(ElementKind.METHOD)) {
|
| + member = classElement.lookUpMethod(_name, _library);
|
| if (member != null) {
|
| return member;
|
| }
|
| }
|
| // getter
|
| - if (kinds.contains(ElementKind.GETTER)) {
|
| - member = classElement.lookUpGetter(name, currentLibrary);
|
| + if (_kinds.contains(ElementKind.GETTER)) {
|
| + member = classElement.lookUpGetter(_name, _library);
|
| if (member != null) {
|
| return member;
|
| }
|
| }
|
| // setter
|
| - if (kinds.contains(ElementKind.SETTER)) {
|
| - member = classElement.lookUpSetter(name + '=', currentLibrary);
|
| + if (_kinds.contains(ElementKind.SETTER)) {
|
| + member = classElement.lookUpSetter(_name + '=', _library);
|
| if (member != null) {
|
| return member;
|
| }
|
|
|