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

Side by Side Diff: pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart

Issue 1516883002: do not suggest completions for cascade on library prefix - fixes #25215 (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: merge 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
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 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 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 analysis_server.src.provisional.completion.dart.completion_target; 5 library analysis_server.src.provisional.completion.dart.completion_target;
6 6
7 import 'package:analyzer/src/generated/ast.dart'; 7 import 'package:analyzer/src/generated/ast.dart';
8 import 'package:analyzer/src/generated/element.dart'; 8 import 'package:analyzer/src/generated/element.dart';
9 import 'package:analyzer/src/generated/scanner.dart'; 9 import 'package:analyzer/src/generated/scanner.dart';
10 import 'package:analyzer/src/generated/utilities_dart.dart'; 10 import 'package:analyzer/src/generated/utilities_dart.dart';
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 * 84 *
85 * Clients may not extend, implement or mix-in this class. 85 * Clients may not extend, implement or mix-in this class.
86 */ 86 */
87 class CompletionTarget { 87 class CompletionTarget {
88 /** 88 /**
89 * The compilation unit in which the completion is occurring. 89 * The compilation unit in which the completion is occurring.
90 */ 90 */
91 final CompilationUnit unit; 91 final CompilationUnit unit;
92 92
93 /** 93 /**
94 * The offset within the source at which the completion is being requested.
95 */
96 final int offset;
97
98 /**
94 * The context in which the completion is occurring. This is the AST node 99 * The context in which the completion is occurring. This is the AST node
95 * which is a direct parent of [entity]. 100 * which is a direct parent of [entity].
96 */ 101 */
97 final AstNode containingNode; 102 final AstNode containingNode;
98 103
99 /** 104 /**
100 * The entity which the completed text will replace (or which will be 105 * The entity which the completed text will replace (or which will be
101 * displaced once the completed text is inserted). This may be an AstNode or 106 * displaced once the completed text is inserted). This may be an AstNode or
102 * a Token, or it may be null if the cursor is after all tokens in the file. 107 * a Token, or it may be null if the cursor is after all tokens in the file.
103 * 108 *
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 } 160 }
156 } 161 }
157 } 162 }
158 for (var entity in containingNode.childEntities) { 163 for (var entity in containingNode.childEntities) {
159 if (entity is Token) { 164 if (entity is Token) {
160 if (_isCandidateToken(entity, offset)) { 165 if (_isCandidateToken(entity, offset)) {
161 // Try to replace with a comment token. 166 // Try to replace with a comment token.
162 Token commentToken = _getContainingCommentToken(entity, offset); 167 Token commentToken = _getContainingCommentToken(entity, offset);
163 if (commentToken != null) { 168 if (commentToken != null) {
164 return new CompletionTarget._( 169 return new CompletionTarget._(
165 compilationUnit, containingNode, commentToken, true); 170 compilationUnit, offset, containingNode, commentToken, true);
166 } 171 }
167 // Target found. 172 // Target found.
168 return new CompletionTarget._( 173 return new CompletionTarget._(
169 compilationUnit, containingNode, entity, false); 174 compilationUnit, offset, containingNode, entity, false);
170 } else { 175 } else {
171 // Since entity is a token, we don't need to look inside it; just 176 // Since entity is a token, we don't need to look inside it; just
172 // proceed to the next entity. 177 // proceed to the next entity.
173 continue; 178 continue;
174 } 179 }
175 } else if (entity is AstNode) { 180 } else if (entity is AstNode) {
176 // If the last token in the node isn't a candidate target, then 181 // If the last token in the node isn't a candidate target, then
177 // neither the node nor any of its descendants can possibly be the 182 // neither the node nor any of its descendants can possibly be the
178 // completion target, so we can skip the node entirely. 183 // completion target, so we can skip the node entirely.
179 if (!_isCandidateToken(entity.endToken, offset)) { 184 if (!_isCandidateToken(entity.endToken, offset)) {
180 continue; 185 continue;
181 } 186 }
182 187
183 // If the node is a candidate target, then we are done. 188 // If the node is a candidate target, then we are done.
184 if (_isCandidateNode(entity, offset)) { 189 if (_isCandidateNode(entity, offset)) {
185 // Check to see if the offset is in a preceding comment 190 // Check to see if the offset is in a preceding comment
186 Token commentToken = 191 Token commentToken =
187 _getContainingCommentToken(entity.beginToken, offset); 192 _getContainingCommentToken(entity.beginToken, offset);
188 if (commentToken != null) { 193 if (commentToken != null) {
189 entity = commentToken; 194 entity = commentToken;
190 // If the preceding comment is dartdoc token, then update 195 // If the preceding comment is dartdoc token, then update
191 // the containing node to be the dartdoc comment. 196 // the containing node to be the dartdoc comment.
192 // Otherwise completion is not required. 197 // Otherwise completion is not required.
193 Comment docComment = 198 Comment docComment =
194 _getContainingDocComment(containingNode, commentToken); 199 _getContainingDocComment(containingNode, commentToken);
195 if (docComment != null) { 200 if (docComment != null) {
196 containingNode = docComment; 201 containingNode = docComment;
197 } else { 202 } else {
198 return new CompletionTarget._( 203 return new CompletionTarget._(compilationUnit, offset,
199 compilationUnit, compilationUnit, commentToken, true); 204 compilationUnit, commentToken, true);
200 } 205 }
201 } 206 }
202 return new CompletionTarget._( 207 return new CompletionTarget._(
203 compilationUnit, containingNode, entity, false); 208 compilationUnit, offset, containingNode, entity, false);
204 } 209 }
205 210
206 // Otherwise, the completion target is somewhere inside the entity, 211 // Otherwise, the completion target is somewhere inside the entity,
207 // so we need to jump to the start of the outer loop to examine its 212 // so we need to jump to the start of the outer loop to examine its
208 // contents. 213 // contents.
209 containingNode = entity; 214 containingNode = entity;
210 continue outerLoop; 215 continue outerLoop;
211 } else { 216 } else {
212 // Unexpected entity found (all entities in a parse tree should be 217 // Unexpected entity found (all entities in a parse tree should be
213 // AST nodes or tokens). 218 // AST nodes or tokens).
214 assert(false); 219 assert(false);
215 } 220 }
216 } 221 }
217 222
218 // No completion target found. It should only be possible to reach here 223 // No completion target found. It should only be possible to reach here
219 // the first time through the outer loop (since we only jump to the start 224 // the first time through the outer loop (since we only jump to the start
220 // of the outer loop after determining that the completion target is 225 // of the outer loop after determining that the completion target is
221 // inside an entity). We can check that assumption by verifying that 226 // inside an entity). We can check that assumption by verifying that
222 // containingNode is still the compilationUnit. 227 // containingNode is still the compilationUnit.
223 assert(identical(containingNode, compilationUnit)); 228 assert(identical(containingNode, compilationUnit));
224 229
225 // Since no completion target was found, we set the completion target 230 // Since no completion target was found, we set the completion target
226 // entity to null and use the compilationUnit as the parent. 231 // entity to null and use the compilationUnit as the parent.
227 return new CompletionTarget._( 232 return new CompletionTarget._(
228 compilationUnit, compilationUnit, null, false); 233 compilationUnit, offset, compilationUnit, null, false);
229 } 234 }
230 } 235 }
231 236
232 /** 237 /**
233 * Create a [CompletionTarget] holding the given [containingNode] and 238 * Create a [CompletionTarget] holding the given [containingNode] and
234 * [entity]. 239 * [entity].
235 */ 240 */
236 CompletionTarget._( 241 CompletionTarget._(this.unit, this.offset, AstNode containingNode,
237 this.unit, AstNode containingNode, Object entity, this.isCommentText) 242 Object entity, this.isCommentText)
238 : this.containingNode = containingNode, 243 : this.containingNode = containingNode,
239 this.entity = entity, 244 this.entity = entity,
240 this.argIndex = _computeArgIndex(containingNode, entity); 245 this.argIndex = _computeArgIndex(containingNode, entity);
241 246
242 /** 247 /**
248 * Return `true` if the [containingNode] is a cascade
249 * and the completion insertion is not between the two dots.
250 * For example, `..d^` and `..^d` are considered a cascade
251 * from a completion standpoint, but `.^.d` is not.
252 */
253 bool get isCascade {
254 AstNode node = containingNode;
255 if (node is PropertyAccess) {
256 return node.isCascaded && offset > node.operator.offset + 1;
257 }
258 if (node is MethodInvocation) {
259 return node.isCascaded && offset > node.operator.offset + 1;
260 }
261 return false;
262 }
263
264 /**
243 * Return `true` if the target is a functional argument in an argument list. 265 * Return `true` if the target is a functional argument in an argument list.
244 * The target [AstNode] hierarchy *must* be resolved for this to work. 266 * The target [AstNode] hierarchy *must* be resolved for this to work.
245 */ 267 */
246 bool isFunctionalArgument() { 268 bool isFunctionalArgument() {
247 if (argIndex == null) { 269 if (argIndex == null) {
248 return false; 270 return false;
249 } 271 }
250 AstNode argList = containingNode; 272 AstNode argList = containingNode;
251 if (argList is! ArgumentList) { 273 if (argList is! ArgumentList) {
252 return false; 274 return false;
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 if (param.parameterKind == ParameterKind.NAMED) { 402 if (param.parameterKind == ParameterKind.NAMED) {
381 // TODO(danrubel) handle named parameters 403 // TODO(danrubel) handle named parameters
382 return false; 404 return false;
383 } else { 405 } else {
384 return paramType is FunctionType || paramType is FunctionTypeAlias; 406 return paramType is FunctionType || paramType is FunctionTypeAlias;
385 } 407 }
386 } 408 }
387 return false; 409 return false;
388 } 410 }
389 } 411 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698