| // Copyright (c) 2015, 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:analysis_server/src/protocol_server.dart' as protocol; |
| import 'package:analysis_server/src/services/search/search_engine.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| |
| class ImplementedComputer { |
| final SearchEngine searchEngine; |
| final CompilationUnitElement unitElement; |
| |
| List<protocol.ImplementedClass> classes = <protocol.ImplementedClass>[]; |
| List<protocol.ImplementedMember> members = <protocol.ImplementedMember>[]; |
| |
| Set<String>? subtypeMembers; |
| |
| ImplementedComputer(this.searchEngine, this.unitElement); |
| |
| Future<void> compute() async { |
| for (var element in unitElement.classes) { |
| await _computeForClassElement(element); |
| } |
| for (var element in unitElement.enums) { |
| await _computeForClassElement(element); |
| } |
| for (var element in unitElement.mixins) { |
| await _computeForClassElement(element); |
| } |
| } |
| |
| void _addImplementedClass(ClassElement type) { |
| var offset = type.nameOffset; |
| var length = type.nameLength; |
| classes.add(protocol.ImplementedClass(offset, length)); |
| } |
| |
| void _addImplementedMember(Element member) { |
| var offset = member.nameOffset; |
| var length = member.nameLength; |
| members.add(protocol.ImplementedMember(offset, length)); |
| } |
| |
| void _addMemberIfImplemented(Element element) { |
| if (element.isSynthetic || _isStatic(element)) { |
| return; |
| } |
| if (_hasOverride(element)) { |
| _addImplementedMember(element); |
| } |
| } |
| |
| Future<void> _computeForClassElement(ClassElement element) async { |
| // Always include Object and its members. |
| if (element.supertype == null && !element.isMixin) { |
| _addImplementedClass(element); |
| element.accessors.forEach(_addImplementedMember); |
| element.fields.forEach(_addImplementedMember); |
| element.methods.forEach(_addImplementedMember); |
| return; |
| } |
| |
| // Analyze subtypes. |
| subtypeMembers = await searchEngine.membersOfSubtypes(element); |
| if (subtypeMembers != null) { |
| _addImplementedClass(element); |
| element.accessors.forEach(_addMemberIfImplemented); |
| element.fields.forEach(_addMemberIfImplemented); |
| element.methods.forEach(_addMemberIfImplemented); |
| } |
| } |
| |
| bool _hasOverride(Element element) { |
| var name = element.displayName; |
| return subtypeMembers!.contains(name); |
| } |
| |
| /// Return `true` if the given [element] is a static element. |
| static bool _isStatic(Element element) { |
| if (element is ExecutableElement) { |
| return element.isStatic; |
| } else if (element is PropertyInducingElement) { |
| return element.isStatic; |
| } |
| return false; |
| } |
| } |