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

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

Issue 1054363003: replace request.node with request.target (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: fix tests Created 5 years, 8 months 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library services.completion.computer.dart.keyword; 5 library services.completion.computer.dart.keyword;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 8
9 import 'package:analysis_server/src/protocol.dart'; 9 import 'package:analysis_server/src/protocol.dart';
10 import 'package:analysis_server/src/services/completion/dart_completion_manager. dart'; 10 import 'package:analysis_server/src/services/completion/dart_completion_manager. dart';
11 import 'package:analyzer/src/generated/ast.dart'; 11 import 'package:analyzer/src/generated/ast.dart';
12 import 'package:analyzer/src/generated/scanner.dart'; 12 import 'package:analyzer/src/generated/scanner.dart';
13 13
14 /** 14 /**
15 * A computer for calculating `completion.getSuggestions` request results 15 * A computer for calculating `completion.getSuggestions` request results
16 * for the local library in which the completion is requested. 16 * for the local library in which the completion is requested.
17 */ 17 */
18 class KeywordComputer extends DartCompletionComputer { 18 class KeywordComputer extends DartCompletionComputer {
19 @override 19 @override
20 bool computeFast(DartCompletionRequest request) { 20 bool computeFast(DartCompletionRequest request) {
21 request.node.accept(new _KeywordVisitor(request)); 21 request.target.containingNode.accept(new _KeywordVisitor(request));
22 return true; 22 return true;
23 } 23 }
24 24
25 @override 25 @override
26 Future<bool> computeFull(DartCompletionRequest request) { 26 Future<bool> computeFull(DartCompletionRequest request) {
27 return new Future.value(false); 27 return new Future.value(false);
28 } 28 }
29 } 29 }
30 30
31 /** 31 /**
32 * A vistor for generating keyword suggestions. 32 * A vistor for generating keyword suggestions.
33 */ 33 */
34 class _KeywordVisitor extends GeneralizingAstVisitor { 34 class _KeywordVisitor extends GeneralizingAstVisitor {
35 final DartCompletionRequest request; 35 final DartCompletionRequest request;
36 final Object entity;
36 37
37 /** 38 _KeywordVisitor(DartCompletionRequest request)
38 * The identifier visited or `null` if not visited. 39 : this.request = request,
39 */ 40 this.entity = request.target.entity;
40 SimpleIdentifier identifier;
41
42 _KeywordVisitor(this.request);
43 41
44 @override 42 @override
45 visitBlock(Block node) { 43 visitBlock(Block node) {
46 if (_isInClassMemberBody(node)) { 44 if (_isInClassMemberBody(node)) {
47 _addSuggestions([ 45 _addSuggestions([Keyword.SUPER, Keyword.THIS,]);
48 Keyword.ASSERT,
49 Keyword.CASE,
50 Keyword.CONTINUE,
51 Keyword.DO,
52 Keyword.FINAL,
53 Keyword.FOR,
54 Keyword.IF,
55 Keyword.NEW,
56 Keyword.RETHROW,
57 Keyword.RETURN,
58 Keyword.SUPER,
59 Keyword.SWITCH,
60 Keyword.THIS,
61 Keyword.THROW,
62 Keyword.TRY,
63 Keyword.VAR,
64 Keyword.VOID,
65 Keyword.WHILE
66 ]);
67 } else {
68 _addSuggestions([
69 Keyword.ASSERT,
70 Keyword.CASE,
71 Keyword.CONTINUE,
72 Keyword.DO,
73 Keyword.FINAL,
74 Keyword.FOR,
75 Keyword.IF,
76 Keyword.NEW,
77 Keyword.RETHROW,
78 Keyword.RETURN,
79 Keyword.SWITCH,
80 Keyword.THROW,
81 Keyword.TRY,
82 Keyword.VAR,
83 Keyword.VOID,
84 Keyword.WHILE
85 ]);
86 } 46 }
47 _addSuggestions([
48 Keyword.ASSERT,
49 Keyword.CASE,
50 Keyword.CONTINUE,
51 Keyword.DO,
52 Keyword.FINAL,
53 Keyword.FOR,
54 Keyword.IF,
55 Keyword.NEW,
56 Keyword.RETHROW,
57 Keyword.RETURN,
58 Keyword.SWITCH,
59 Keyword.THROW,
60 Keyword.TRY,
61 Keyword.VAR,
62 Keyword.VOID,
63 Keyword.WHILE
64 ]);
87 } 65 }
88 66
89 @override 67 @override
90 visitClassDeclaration(ClassDeclaration node) { 68 visitClassDeclaration(ClassDeclaration node) {
91 // Don't suggest class name 69 // Don't suggest class name
92 if (node.name == identifier) { 70 if (entity == node.name) {
93 return; 71 return;
94 } 72 }
95 // Inside the class declaration { } 73 if (entity == node.rightBracket) {
Paul Berry 2015/04/03 19:04:29 Shouldn't these suggestions also be made if entity
danrubel 2015/04/03 20:54:01 Good catch! https://codereview.chromium.org/105740
96 if (request.offset > node.leftBracket.offset) {
97 _addSuggestions([ 74 _addSuggestions([
98 Keyword.CONST, 75 Keyword.CONST,
99 Keyword.DYNAMIC, 76 Keyword.DYNAMIC,
100 Keyword.FACTORY, 77 Keyword.FACTORY,
101 Keyword.FINAL, 78 Keyword.FINAL,
102 Keyword.GET, 79 Keyword.GET,
103 Keyword.OPERATOR, 80 Keyword.OPERATOR,
104 Keyword.SET, 81 Keyword.SET,
105 Keyword.STATIC, 82 Keyword.STATIC,
106 Keyword.VAR, 83 Keyword.VAR,
107 Keyword.VOID 84 Keyword.VOID
108 ]); 85 ]);
109 return; 86 return;
110 } 87 }
111 _addClassDeclarationKeywords(node); 88 _addClassDeclarationKeywords(node);
112 } 89 }
113 90
114 @override 91 @override
115 visitCompilationUnit(CompilationUnit node) { 92 visitCompilationUnit(CompilationUnit node) {
116 Directive firstDirective; 93 var previousMember = null;
117 int endOfDirectives = 0; 94 for (var member in node.childEntities) {
118 if (node.directives.length > 0) { 95 if (entity == member) {
119 firstDirective = node.directives[0]; 96 break;
120 endOfDirectives = node.directives.last.end - 1; 97 }
98 previousMember = member;
121 } 99 }
122 int startOfDeclarations = node.end; 100 if (previousMember is ClassDeclaration) {
123 if (node.declarations.length > 0) { 101 if (previousMember.leftBracket == null ||
124 startOfDeclarations = node.declarations[0].offset; 102 previousMember.leftBracket.isSynthetic) {
125 // If the first token is a simple identifier 103 // If the prior member is an unfinished class declaration
126 // and cursor position in within that first token 104 // then the user is probably finishing that
127 // then consider cursor to be before the first declaration 105 _addClassDeclarationKeywords(previousMember);
128 Token token = node.declarations[0].firstTokenAfterCommentAndMetadata; 106 return;
129 if (token.offset <= request.offset && request.offset <= token.end) {
130 startOfDeclarations = token.end;
131 } 107 }
132 } 108 }
133 109 if (previousMember == null || previousMember is Directive) {
134 // Simplistic check for library as first directive 110 if (previousMember == null &&
135 if (firstDirective is! LibraryDirective) { 111 !node.directives.any((d) => d is LibraryDirective)) {
136 if (firstDirective != null) { 112 _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH);
137 if (request.offset <= firstDirective.offset) {
138 _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH);
139 }
140 } else {
141 if (request.offset <= startOfDeclarations) {
142 _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH);
143 }
144 } 113 }
145 }
146 if (request.offset <= startOfDeclarations) {
147 _addSuggestions( 114 _addSuggestions(
148 [Keyword.EXPORT, Keyword.IMPORT, Keyword.PART], DART_RELEVANCE_HIGH); 115 [Keyword.EXPORT, Keyword.IMPORT, Keyword.PART], DART_RELEVANCE_HIGH);
149 } 116 }
150 if (request.offset >= endOfDirectives) { 117 if (entity == null || entity is Declaration) {
151 _addSuggestions([ 118 _addSuggestions([
152 Keyword.ABSTRACT, 119 Keyword.ABSTRACT,
153 Keyword.CLASS, 120 Keyword.CLASS,
154 Keyword.CONST, 121 Keyword.CONST,
155 Keyword.FINAL, 122 Keyword.FINAL,
156 Keyword.TYPEDEF, 123 Keyword.TYPEDEF,
157 Keyword.VAR 124 Keyword.VAR
158 ], DART_RELEVANCE_HIGH); 125 ], DART_RELEVANCE_HIGH);
159 } 126 }
160 } 127 }
161 128
162 @override
163 visitNode(AstNode node) {
164 if (_isOffsetAfterNode(node)) {
165 node.parent.accept(this);
166 }
167 }
168
169 visitSimpleIdentifier(SimpleIdentifier node) {
170 identifier = node;
171 node.parent.accept(this);
172 }
173
174 void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
175 if (identifier != null && node.beginToken == identifier.beginToken) {
176 AstNode unit = node.parent;
177 if (unit is CompilationUnit) {
178 CompilationUnitMember previous;
179 for (CompilationUnitMember member in unit.declarations) {
180 if (member == node && previous is ClassDeclaration) {
181 if (previous.endToken.isSynthetic) {
182 // Partial keywords (simple identifirs) that are part of a
183 // class declaration can be parsed
184 // as a TypeName in a TopLevelVariableDeclaration
185 _addClassDeclarationKeywords(previous);
186 return;
187 }
188 }
189 previous = member;
190 }
191 // Partial keywords (simple identifiers) can be parsed
192 // as a TypeName in a TopLevelVariableDeclaration
193 unit.accept(this);
194 }
195 }
196 }
197
198 void visitTypeName(TypeName node) {
199 node.parent.accept(this);
200 }
201
202 void visitVariableDeclarationList(VariableDeclarationList node) {
203 node.parent.accept(this);
204 }
205
206 void _addClassDeclarationKeywords(ClassDeclaration node) { 129 void _addClassDeclarationKeywords(ClassDeclaration node) {
207 // Very simplistic suggestion because analyzer will warn if 130 // Very simplistic suggestion because analyzer will warn if
208 // the extends / with / implements keywords are out of order 131 // the extends / with / implements keywords are out of order
209 if (node.extendsClause == null) { 132 if (node.extendsClause == null) {
210 _addSuggestion(Keyword.EXTENDS, DART_RELEVANCE_HIGH); 133 _addSuggestion(Keyword.EXTENDS, DART_RELEVANCE_HIGH);
211 } else if (node.withClause == null) { 134 } else if (node.withClause == null) {
212 _addSuggestion(Keyword.WITH, DART_RELEVANCE_HIGH); 135 _addSuggestion(Keyword.WITH, DART_RELEVANCE_HIGH);
213 } 136 }
214 if (node.implementsClause == null) { 137 if (node.implementsClause == null) {
215 _addSuggestion(Keyword.IMPLEMENTS, DART_RELEVANCE_HIGH); 138 _addSuggestion(Keyword.IMPLEMENTS, DART_RELEVANCE_HIGH);
216 } 139 }
217 } 140 }
218 141
219 void _addSuggestion(Keyword keyword, 142 void _addSuggestion(Keyword keyword,
220 [int relevance = DART_RELEVANCE_DEFAULT]) { 143 [int relevance = DART_RELEVANCE_DEFAULT]) {
221 String completion = keyword.syntax; 144 String completion = keyword.syntax;
222 request.addSuggestion(new CompletionSuggestion( 145 request.addSuggestion(new CompletionSuggestion(
223 CompletionSuggestionKind.KEYWORD, 146 CompletionSuggestionKind.KEYWORD, relevance, completion,
224 relevance, completion, completion.length, 0, false, false)); 147 completion.length, 0, false, false));
225 } 148 }
226 149
227 void _addSuggestions(List<Keyword> keywords, 150 void _addSuggestions(List<Keyword> keywords,
228 [int relevance = DART_RELEVANCE_KEYWORD]) { 151 [int relevance = DART_RELEVANCE_KEYWORD]) {
229 keywords.forEach((Keyword keyword) { 152 keywords.forEach((Keyword keyword) {
230 _addSuggestion(keyword, relevance); 153 _addSuggestion(keyword, relevance);
231 }); 154 });
232 } 155 }
233 156
234 bool _isOffsetAfterNode(AstNode node) { 157 bool _isInClassMemberBody(AstNode node) {
235 if (request.offset == node.end) {
236 Token token = node.endToken;
237 if (token != null && !token.isSynthetic) {
238 if (token.lexeme == ';' || token.lexeme == '}') {
239 return true;
240 }
241 }
242 }
243 return false;
244 }
245
246 static bool _isInClassMemberBody(AstNode node) {
Paul Berry 2015/04/03 19:04:29 Any particular reason for dropping the "static" ke
247 while (true) { 158 while (true) {
248 AstNode body = node.getAncestor((n) => n is FunctionBody); 159 AstNode body = node.getAncestor((n) => n is FunctionBody);
249 if (body == null) { 160 if (body == null) {
250 return false; 161 return false;
251 } 162 }
252 AstNode parent = body.parent; 163 AstNode parent = body.parent;
253 if (parent is ConstructorDeclaration || parent is MethodDeclaration) { 164 if (parent is ConstructorDeclaration || parent is MethodDeclaration) {
254 return true; 165 return true;
255 } 166 }
256 node = parent; 167 node = parent;
257 } 168 }
258 } 169 }
259 } 170 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698