| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2015, 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 library services.completion.dart.invocation; | |
| 6 | |
| 7 import 'dart:async'; | |
| 8 | |
| 9 import 'package:analysis_server/src/protocol_server.dart' | |
| 10 show CompletionSuggestion, CompletionSuggestionKind, SourceChange; | |
| 11 import 'package:analysis_server/src/protocol_server.dart' as protocol | |
| 12 hide CompletionSuggestion, CompletionSuggestionKind; | |
| 13 import 'package:analysis_server/src/provisional/completion/completion_core.dart'
; | |
| 14 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.
dart'; | |
| 15 import 'package:analysis_server/src/provisional/completion/dart/completion_targe
t.dart'; | |
| 16 import 'package:analyzer/dart/element/element.dart'; | |
| 17 import 'package:analyzer/src/generated/ast.dart'; | |
| 18 import 'package:analyzer/src/generated/resolver.dart'; | |
| 19 import 'package:analyzer/src/generated/source.dart'; | |
| 20 | |
| 21 /** | |
| 22 * A completion contributor used to suggest replacing partial identifiers inside | |
| 23 * a class declaration with templates for inherited members. | |
| 24 */ | |
| 25 class InheritedContributor implements DartCompletionContributor { | |
| 26 @override | |
| 27 Future<List<CompletionSuggestion>> computeSuggestions( | |
| 28 DartCompletionRequest request) async { | |
| 29 SimpleIdentifier targetId = _getTargetId(request.target); | |
| 30 if (targetId == null) { | |
| 31 return EMPTY_LIST; | |
| 32 } | |
| 33 ClassDeclaration classDecl = | |
| 34 targetId.getAncestor((p) => p is ClassDeclaration); | |
| 35 if (classDecl == null) { | |
| 36 return EMPTY_LIST; | |
| 37 } | |
| 38 | |
| 39 // Generate a collection of inherited members | |
| 40 ClassElement classElem = classDecl.element; | |
| 41 InheritanceManager manager = new InheritanceManager(classElem.library); | |
| 42 MemberMap map = manager.getMapOfMembersInheritedFromInterfaces(classElem); | |
| 43 List<String> memberNames = _computeMemberNames(map, classElem); | |
| 44 | |
| 45 // Build suggestions | |
| 46 List<CompletionSuggestion> suggestions = <CompletionSuggestion>[]; | |
| 47 for (String memberName in memberNames) { | |
| 48 ExecutableElement element = map.get(memberName); | |
| 49 // Gracefully degrade if the overridden element has not been resolved. | |
| 50 if (element.returnType != null) { | |
| 51 CompletionSuggestion suggestion = | |
| 52 _buildSuggestion(request, targetId, element); | |
| 53 if (suggestion != null) { | |
| 54 suggestions.add(suggestion); | |
| 55 } | |
| 56 } | |
| 57 } | |
| 58 return suggestions; | |
| 59 } | |
| 60 | |
| 61 /** | |
| 62 * Return a template for an override of the given [element] in the given | |
| 63 * [source]. If selected, the template will replace [targetId]. | |
| 64 */ | |
| 65 String _buildRepacementText(Source source, SimpleIdentifier targetId, | |
| 66 CompilationUnit unit, ExecutableElement element) { | |
| 67 // AnalysisContext context = element.context; | |
| 68 // Inject partially resolved unit for use by change builder | |
| 69 // DartChangeBuilder builder = new DartChangeBuilder(context, unit); | |
| 70 // builder.addFileEdit(source, context.getModificationStamp(source), | |
| 71 // (DartFileEditBuilder builder) { | |
| 72 // builder.addReplacement(targetId.offset, targetId.length, | |
| 73 // (DartEditBuilder builder) { | |
| 74 // builder.writeOverrideOfInheritedMember(element); | |
| 75 // }); | |
| 76 // }); | |
| 77 // return builder.sourceChange.edits[0].edits[0].replacement.trim(); | |
| 78 return ''; | |
| 79 } | |
| 80 | |
| 81 /** | |
| 82 * Build a suggestion to replace [targetId] in the given [unit] | |
| 83 * with an override of the given [element]. | |
| 84 */ | |
| 85 CompletionSuggestion _buildSuggestion(DartCompletionRequest request, | |
| 86 SimpleIdentifier targetId, ExecutableElement element) { | |
| 87 String completion = _buildRepacementText( | |
| 88 request.source, targetId, request.target.unit, element); | |
| 89 if (completion == null || completion.length == 0) { | |
| 90 return null; | |
| 91 } | |
| 92 CompletionSuggestion suggestion = new CompletionSuggestion( | |
| 93 CompletionSuggestionKind.IDENTIFIER, | |
| 94 DART_RELEVANCE_HIGH, | |
| 95 completion, | |
| 96 targetId.offset, | |
| 97 0, | |
| 98 element.isDeprecated, | |
| 99 false); | |
| 100 suggestion.element = protocol.convertElement(element); | |
| 101 return suggestion; | |
| 102 } | |
| 103 | |
| 104 /** | |
| 105 * Return a list containing the names of all of the inherited but not | |
| 106 * implemented members of the class represented by the given [element]. | |
| 107 * The [map] is used to find all of the members that are inherited. | |
| 108 */ | |
| 109 List<String> _computeMemberNames(MemberMap map, ClassElement element) { | |
| 110 List<String> memberNames = <String>[]; | |
| 111 int count = map.size; | |
| 112 for (int i = 0; i < count; i++) { | |
| 113 String memberName = map.getKey(i); | |
| 114 if (!_hasMember(element, memberName)) { | |
| 115 memberNames.add(memberName); | |
| 116 } | |
| 117 } | |
| 118 return memberNames; | |
| 119 } | |
| 120 | |
| 121 /** | |
| 122 * If the target looks like a partial identifier inside a class declaration | |
| 123 * then return that identifier, otherwise return `null`. | |
| 124 */ | |
| 125 SimpleIdentifier _getTargetId(CompletionTarget target) { | |
| 126 AstNode node = target.containingNode; | |
| 127 if (node is ClassDeclaration) { | |
| 128 Object entity = target.entity; | |
| 129 if (entity is FieldDeclaration) { | |
| 130 NodeList<VariableDeclaration> variables = entity.fields.variables; | |
| 131 if (variables.length == 1) { | |
| 132 SimpleIdentifier targetId = variables[0].name; | |
| 133 if (targetId.name.isEmpty) { | |
| 134 return targetId; | |
| 135 } | |
| 136 } | |
| 137 } | |
| 138 } | |
| 139 return null; | |
| 140 } | |
| 141 | |
| 142 /** | |
| 143 * Return `true` if the given [classElement] directly declares a member with | |
| 144 * the given [memberName]. | |
| 145 */ | |
| 146 bool _hasMember(ClassElement classElement, String memberName) { | |
| 147 return classElement.getField(memberName) != null || | |
| 148 classElement.getGetter(memberName) != null || | |
| 149 classElement.getMethod(memberName) != null || | |
| 150 classElement.getSetter(memberName) != null; | |
| 151 } | |
| 152 } | |
| OLD | NEW |