Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(108)

Side by Side Diff: pkg/analysis_server/lib/src/services/completion/dart/inherited_contributor.dart

Issue 1467023002: step toward new completion API (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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.computer.dart.invocation;
6
7 import 'dart:async';
8
9 import 'package:analysis_server/plugin/edit/utilities/change_builder_dart.dart';
10 import 'package:analysis_server/src/protocol_server.dart'
11 show CompletionSuggestion, CompletionSuggestionKind, SourceChange;
12 import 'package:analysis_server/src/protocol_server.dart' as protocol
13 hide CompletionSuggestion, CompletionSuggestionKind;
14 import 'package:analysis_server/src/provisional/completion/completion_dart.dart' ;
15 import 'package:analysis_server/src/provisional/completion/dart/completion_targe t.dart';
16 import 'package:analysis_server/src/services/completion/dart_completion_manager. dart'
17 show DART_RELEVANCE_HIGH;
18 import 'package:analyzer/src/generated/ast.dart';
19 import 'package:analyzer/src/generated/element.dart';
20 import 'package:analyzer/src/generated/engine.dart';
21 import 'package:analyzer/src/generated/resolver.dart';
22 import 'package:analyzer/src/generated/source.dart';
23
24 /**
25 * A completion contributor used to suggest replacing partial identifiers inside
26 * a class declaration with templates for inherited members.
27 */
28 class InheritedContributor implements DartCompletionContributor {
29 @override
30 Future<List<CompletionSuggestion>> computeSuggestions(
31 DartCompletionRequest request) async {
32 // Determine if the target looks like a partial identifier
33 // inside a class declaration
34 SimpleIdentifier targetId = _getTargetId(request.target);
35 if (targetId == null) {
36 return null;
Brian Wilkerson 2015/11/22 18:02:46 The documentation for this method doesn't mention
danrubel 2015/11/23 17:47:32 Done.
37 }
38
39 // Partially resolve the compilation unit
scheglov 2015/11/22 05:19:02 If we pretend that these are sentences, I'd love t
danrubel 2015/11/23 17:47:32 Acknowledged.
40 CompilationUnit unit = await request.resolveDeclarationsInScope();
41 // Gracefully degrade if the compilation unit could not be resolved
42 // e.g. detached part file or source change
43 if (unit == null) {
44 return null;
45 }
46
47 // Recompute the target since resolution may have changed it
48 targetId = _getTargetId(request.target);
49 if (targetId == null) {
50 return null;
51 }
52 ClassDeclaration classDecl =
53 targetId.getAncestor((p) => p is ClassDeclaration);
54 if (classDecl == null) {
55 return null;
56 }
57
58 // Generate a collection of inherited members
59 ClassElement classElem = classDecl.element;
60 InheritanceManager manager = new InheritanceManager(classElem.library);
61 MemberMap map = manager.getMapOfMembersInheritedFromInterfaces(classElem);
62 List<String> memberNames = _computeMemberNames(map, classElem);
63
64 // Build suggestions
65 List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
66 for (String memberName in memberNames) {
67 ExecutableElement element = map.get(memberName);
68 // Gracefully degrade if the overridden element has not been resolved.
Brian Wilkerson 2015/11/22 18:02:47 Is that actually necessary? We already have the co
danrubel 2015/11/23 17:47:32 I have found situations where the element has not
69 if (element.returnType != null) {
70 CompletionSuggestion suggestion =
71 _buildSuggestion(request, targetId, unit, element);
72 if (suggestion != null) {
scheglov 2015/11/22 05:19:02 It seems that it cannot be null.
danrubel 2015/11/23 17:47:32 It can now. :-)
73 suggestions.add(suggestion);
74 }
75 }
76 }
77 return suggestions;
78 }
79
80 /**
81 * If the target looks like a partial identifier inside a class declaration
82 * then return that identifier, otherwise return `null`.
83 */
84 SimpleIdentifier _getTargetId(CompletionTarget target) {
85 AstNode node = target.containingNode;
86 if (node is ClassDeclaration) {
87 Object entity = target.entity;
88 if (entity is FieldDeclaration) {
89 NodeList<VariableDeclaration> variables = entity.fields.variables;
90 if (variables.length == 1) {
91 SimpleIdentifier targetId = variables[0].name;
92 if (targetId.name.isEmpty) {
93 return targetId;
94 }
95 }
96 }
97 }
98 return null;
99 }
100
101 /**
102 * Return a template for an override of the given [element] in the given
103 * [source]. If selected, the template will replace [targetId].
104 */
105 String _buildRepacementText(Source source, SimpleIdentifier targetId,
106 CompilationUnit unit, Element element) {
Brian Wilkerson 2015/11/22 18:02:47 "Element" --> "ExecutableElement"
danrubel 2015/11/23 17:47:32 Done.
107 AnalysisContext context = element.context;
108 DartChangeBuilder builder = new DartChangeBuilder(context, unit);
109 builder.addFileEdit(source, context.getModificationStamp(source),
110 (DartFileEditBuilder builder) {
111 builder.addReplacement(targetId.offset, targetId.length,
112 (DartEditBuilder builder) {
113 builder.writeOverrideOfInheritedMember(element);
114 });
115 });
116 return builder.sourceChange.edits[0].edits[0].replacement.trim();
117 }
118
119 /**
120 * Build a suggestion to replace [targetId] in the given [unit]
121 * with an override of the given [element].
122 */
123 CompletionSuggestion _buildSuggestion(DartCompletionRequest request,
124 SimpleIdentifier targetId, CompilationUnit unit, Element element) {
Brian Wilkerson 2015/11/22 18:02:47 "Element" --> "ExecutableElement"
danrubel 2015/11/23 17:47:32 Done.
125 String completion =
126 _buildRepacementText(request.source, targetId, unit, element);
127 CompletionSuggestion suggestion = new CompletionSuggestion(
128 CompletionSuggestionKind.IDENTIFIER,
129 DART_RELEVANCE_HIGH,
130 completion,
131 targetId.offset,
132 0,
133 element.isDeprecated,
134 false);
135 suggestion.element = protocol.convertElement(element);
136 return suggestion;
137 }
138
139 /**
140 * Return a list containing the names of all of the inherited but not
141 * implemented members of the class represented by the given [element].
142 * The [map] is used to find all of the members that are inherited.
143 */
144 List<String> _computeMemberNames(MemberMap map, ClassElement element) {
145 List<String> memberNames = <String>[];
146 int count = map.size;
147 for (int i = 0; i < count; i++) {
148 String memberName = map.getKey(i);
149 if (!_hasMember(element, memberName)) {
150 memberNames.add(memberName);
151 }
152 }
153 return memberNames;
154 }
155
156 /**
157 * Return `true` if the given [classElement] directly declares a member with
158 * the given [memberName].
159 */
160 bool _hasMember(ClassElement classElement, String memberName) {
161 return classElement.getField(memberName) != null ||
162 classElement.getGetter(memberName) != null ||
163 classElement.getMethod(memberName) != null ||
164 classElement.getSetter(memberName) != null;
165 }
166 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698