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

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

Issue 2679503002: suggest method references in named expressions (Closed)
Patch Set: merge Created 3 years, 10 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
« no previous file with comments | « no previous file | pkg/analysis_server/test/services/completion/completion_target_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/dart/ast/ast.dart'; 7 import 'package:analyzer/dart/ast/ast.dart';
8 import 'package:analyzer/dart/ast/token.dart'; 8 import 'package:analyzer/dart/ast/token.dart';
9 import 'package:analyzer/dart/element/element.dart'; 9 import 'package:analyzer/dart/element/element.dart';
10 import 'package:analyzer/dart/element/type.dart'; 10 import 'package:analyzer/dart/element/type.dart';
11 import 'package:analyzer/src/generated/utilities_dart.dart'; 11 import 'package:analyzer/src/generated/utilities_dart.dart';
12 12
13 int _computeArgIndex(AstNode containingNode, Object entity) { 13 int _computeArgIndex(AstNode containingNode, Object entity) {
14 var argList = containingNode; 14 var argList = containingNode;
15 if (argList is NamedExpression) {
16 entity = argList;
17 argList = argList.parent;
18 }
15 if (argList is ArgumentList) { 19 if (argList is ArgumentList) {
16 NodeList<Expression> args = argList.arguments; 20 NodeList<Expression> args = argList.arguments;
17 for (int index = 0; index < args.length; ++index) { 21 for (int index = 0; index < args.length; ++index) {
18 if (entity == args[index]) { 22 if (entity == args[index]) {
19 return index; 23 return index;
20 } 24 }
21 } 25 }
22 if (args.isEmpty) { 26 if (args.isEmpty) {
23 return 0; 27 return 0;
24 } 28 }
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 134
131 /** 135 /**
132 * If the target is an argument in an [ArgumentList], then this is the index 136 * If the target is an argument in an [ArgumentList], then this is the index
133 * of the argument in the list, otherwise this is `null`. 137 * of the argument in the list, otherwise this is `null`.
134 */ 138 */
135 final int argIndex; 139 final int argIndex;
136 140
137 /** 141 /**
138 * Compute the appropriate [CompletionTarget] for the given [offset] within 142 * Compute the appropriate [CompletionTarget] for the given [offset] within
139 * the [compilationUnit]. 143 * the [compilationUnit].
140 * 144 *
141 * Optionally, start the search from within [entryPoint] instead of using 145 * Optionally, start the search from within [entryPoint] instead of using
142 * the [compilationUnit], which is useful for analyzing ASTs that have no 146 * the [compilationUnit], which is useful for analyzing ASTs that have no
143 * [compilationUnit] such as dart expressions within angular templates. 147 * [compilationUnit] such as dart expressions within angular templates.
144 */ 148 */
145 factory CompletionTarget.forOffset( 149 factory CompletionTarget.forOffset(
146 CompilationUnit compilationUnit, int offset, {AstNode entryPoint}) { 150 CompilationUnit compilationUnit, int offset,
151 {AstNode entryPoint}) {
147 // The precise algorithm is as follows. We perform a depth-first search of 152 // The precise algorithm is as follows. We perform a depth-first search of
148 // all edges in the parse tree (both those that point to AST nodes and 153 // all edges in the parse tree (both those that point to AST nodes and
149 // those that point to tokens), visiting parents before children. The 154 // those that point to tokens), visiting parents before children. The
150 // first edge which points to an entity satisfying either _isCandidateToken 155 // first edge which points to an entity satisfying either _isCandidateToken
151 // or _isCandidateNode is the completion target. If no edge is found that 156 // or _isCandidateNode is the completion target. If no edge is found that
152 // satisfies these two predicates, then we set the completion target entity 157 // satisfies these two predicates, then we set the completion target entity
153 // to null and the containingNode to the entryPoint. 158 // to null and the containingNode to the entryPoint.
154 // 159 //
155 // Note that if a token is not a candidate target, then none of the tokens 160 // Note that if a token is not a candidate target, then none of the tokens
156 // that precede it are candidate targets either. Therefore any entity 161 // that precede it are candidate targets either. Therefore any entity
157 // whose last token is not a candidate target can be skipped. This lets us 162 // whose last token is not a candidate target can be skipped. This lets us
158 // prune the search to the point where no recursion is necessary; at each 163 // prune the search to the point where no recursion is necessary; at each
159 // step in the process we know exactly which child node we need to proceed 164 // step in the process we know exactly which child node we need to proceed
160 // to. 165 // to.
161 entryPoint ??= compilationUnit; 166 entryPoint ??= compilationUnit;
162 AstNode containingNode = entryPoint; 167 AstNode containingNode = entryPoint;
163 outerLoop: while (true) { 168 outerLoop:
169 while (true) {
164 if (containingNode is Comment) { 170 if (containingNode is Comment) {
165 // Comments are handled specially: we descend into any CommentReference 171 // Comments are handled specially: we descend into any CommentReference
166 // child node that contains the cursor offset. 172 // child node that contains the cursor offset.
167 Comment comment = containingNode; 173 Comment comment = containingNode;
168 for (CommentReference commentReference in comment.references) { 174 for (CommentReference commentReference in comment.references) {
169 if (commentReference.offset <= offset && 175 if (commentReference.offset <= offset &&
170 offset <= commentReference.end) { 176 offset <= commentReference.end) {
171 containingNode = commentReference; 177 containingNode = commentReference;
172 continue outerLoop; 178 continue outerLoop;
173 } 179 }
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 /** 283 /**
278 * Return `true` if the target is a functional argument in an argument list. 284 * Return `true` if the target is a functional argument in an argument list.
279 * The target [AstNode] hierarchy *must* be resolved for this to work. 285 * The target [AstNode] hierarchy *must* be resolved for this to work.
280 * See [maybeFunctionalArgument]. 286 * See [maybeFunctionalArgument].
281 */ 287 */
282 bool isFunctionalArgument() { 288 bool isFunctionalArgument() {
283 if (!maybeFunctionalArgument()) { 289 if (!maybeFunctionalArgument()) {
284 return false; 290 return false;
285 } 291 }
286 AstNode parent = containingNode.parent; 292 AstNode parent = containingNode.parent;
293 if (parent is ArgumentList) {
294 parent = parent.parent;
295 }
287 if (parent is InstanceCreationExpression) { 296 if (parent is InstanceCreationExpression) {
288 DartType instType = parent.bestType; 297 DartType instType = parent.bestType;
289 if (instType != null) { 298 if (instType != null) {
290 Element intTypeElem = instType.element; 299 Element intTypeElem = instType.element;
291 if (intTypeElem is ClassElement) { 300 if (intTypeElem is ClassElement) {
292 SimpleIdentifier constructorName = parent.constructorName.name; 301 SimpleIdentifier constructorName = parent.constructorName.name;
293 ConstructorElement constructor = constructorName != null 302 ConstructorElement constructor = constructorName != null
294 ? intTypeElem.getNamedConstructor(constructorName.name) 303 ? intTypeElem.getNamedConstructor(constructorName.name)
295 : intTypeElem.unnamedConstructor; 304 : intTypeElem.unnamedConstructor;
296 return constructor != null && 305 return constructor != null &&
297 _isFunctionalParameter(constructor.parameters, argIndex); 306 _isFunctionalParameter(
307 constructor.parameters, argIndex, containingNode);
298 } 308 }
299 } 309 }
300 } else if (parent is MethodInvocation) { 310 } else if (parent is MethodInvocation) {
301 SimpleIdentifier methodName = parent.methodName; 311 SimpleIdentifier methodName = parent.methodName;
302 if (methodName != null) { 312 if (methodName != null) {
303 Element methodElem = methodName.bestElement; 313 Element methodElem = methodName.bestElement;
304 if (methodElem is MethodElement) { 314 if (methodElem is MethodElement) {
305 return _isFunctionalParameter(methodElem.parameters, argIndex); 315 return _isFunctionalParameter(
316 methodElem.parameters, argIndex, containingNode);
306 } else if (methodElem is FunctionElement) { 317 } else if (methodElem is FunctionElement) {
307 return _isFunctionalParameter(methodElem.parameters, argIndex); 318 return _isFunctionalParameter(
319 methodElem.parameters, argIndex, containingNode);
308 } 320 }
309 } 321 }
310 } 322 }
311 return false; 323 return false;
312 } 324 }
313 325
314 /** 326 /**
315 * Return `true` if the target maybe a functional argument in an argument list . 327 * Return `true` if the target maybe a functional argument in an argument list .
316 * This is used in determining whether the target [AstNode] hierarchy 328 * This is used in determining whether the target [AstNode] hierarchy
317 * needs to be resolved so that [isFunctionalArgument] will work. 329 * needs to be resolved so that [isFunctionalArgument] will work.
318 */ 330 */
319 bool maybeFunctionalArgument() { 331 bool maybeFunctionalArgument() {
320 if (argIndex == null) { 332 if (argIndex != null) {
321 return false; 333 if (containingNode is ArgumentList) {
334 return true;
335 }
336 if (containingNode is NamedExpression) {
337 if (containingNode.parent is ArgumentList) {
338 return true;
339 }
340 }
322 } 341 }
323 AstNode argList = containingNode; 342 return false;
324 if (argList is! ArgumentList) {
325 return false;
326 }
327 return true;
328 } 343 }
329 344
330 /** 345 /**
331 * Determine if the offset is contained in a preceding comment token 346 * Determine if the offset is contained in a preceding comment token
332 * and return that token, otherwise return `null`. 347 * and return that token, otherwise return `null`.
333 */ 348 */
334 static Token _getContainingCommentToken(Token token, int offset) { 349 static Token _getContainingCommentToken(Token token, int offset) {
335 if (token == null) { 350 if (token == null) {
336 return null; 351 return null;
337 } 352 }
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 return token.type == TokenType.KEYWORD || 428 return token.type == TokenType.KEYWORD ||
414 previous.type == TokenType.IDENTIFIER; 429 previous.type == TokenType.IDENTIFIER;
415 } else { 430 } else {
416 return false; 431 return false;
417 } 432 }
418 } 433 }
419 434
420 /** 435 /**
421 * Return `true` if the parameter is a functional parameter. 436 * Return `true` if the parameter is a functional parameter.
422 */ 437 */
423 static bool _isFunctionalParameter( 438 static bool _isFunctionalParameter(List<ParameterElement> parameters,
424 List<ParameterElement> parameters, int paramIndex) { 439 int paramIndex, AstNode containingNode) {
440 DartType paramType;
425 if (paramIndex < parameters.length) { 441 if (paramIndex < parameters.length) {
426 ParameterElement param = parameters[paramIndex]; 442 ParameterElement param = parameters[paramIndex];
427 DartType paramType = param.type;
428 if (param.parameterKind == ParameterKind.NAMED) { 443 if (param.parameterKind == ParameterKind.NAMED) {
429 // TODO(danrubel) handle named parameters 444 if (containingNode is NamedExpression) {
430 return false; 445 String name = containingNode.name?.label?.name;
446 param = parameters.firstWhere(
447 (ParameterElement param) =>
448 param.parameterKind == ParameterKind.NAMED &&
449 param.name == name,
450 orElse: () => null);
451 paramType = param?.type;
452 }
431 } else { 453 } else {
432 return paramType is FunctionType || paramType is FunctionTypeAlias; 454 paramType = param.type;
433 } 455 }
434 } 456 }
435 return false; 457 return paramType is FunctionType || paramType is FunctionTypeAlias;
436 } 458 }
437 } 459 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analysis_server/test/services/completion/completion_target_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698