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

Side by Side Diff: pkg/analysis_server/lib/src/services/refactoring/inline_method.dart

Issue 565973006: Issue 19800. Support for inlining getters/setters. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 3 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.src.refactoring.inline_method; 5 library services.src.refactoring.inline_method;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 8
9 import 'package:analysis_server/src/protocol.dart' hide Element; 9 import 'package:analysis_server/src/protocol.dart' hide Element;
10 import 'package:analysis_server/src/services/correction/source_range.dart'; 10 import 'package:analysis_server/src/services/correction/source_range.dart';
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 final int offset; 172 final int offset;
173 String file; 173 String file;
174 CorrectionUtils utils; 174 CorrectionUtils utils;
175 SourceChange change; 175 SourceChange change;
176 176
177 bool isDeclaration = false; 177 bool isDeclaration = false;
178 bool deleteSource = false; 178 bool deleteSource = false;
179 bool inlineAll = true; 179 bool inlineAll = true;
180 180
181 ExecutableElement _methodElement; 181 ExecutableElement _methodElement;
182 bool _isAccessor;
182 String _methodFile; 183 String _methodFile;
183 CompilationUnit _methodUnit; 184 CompilationUnit _methodUnit;
184 CorrectionUtils _methodUtils; 185 CorrectionUtils _methodUtils;
185 AstNode _methodNode; 186 AstNode _methodNode;
186 FormalParameterList _methodParameters; 187 FormalParameterList _methodParameters;
187 FunctionBody _methodBody; 188 FunctionBody _methodBody;
188 Expression _methodExpression; 189 Expression _methodExpression;
189 _SourcePart _methodExpressionPart; 190 _SourcePart _methodExpressionPart;
190 _SourcePart _methodStatementsPart; 191 _SourcePart _methodStatementsPart;
191 List<_ReferenceProcessor> _referenceProcessors = []; 192 List<_ReferenceProcessor> _referenceProcessors = [];
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 295
295 /** 296 /**
296 * Initializes [_methodElement] and related fields. 297 * Initializes [_methodElement] and related fields.
297 */ 298 */
298 RefactoringStatus _prepareMethod() { 299 RefactoringStatus _prepareMethod() {
299 _methodElement = null; 300 _methodElement = null;
300 _methodParameters = null; 301 _methodParameters = null;
301 _methodBody = null; 302 _methodBody = null;
302 deleteSource = false; 303 deleteSource = false;
303 inlineAll = false; 304 inlineAll = false;
305 // prepare for failure
306 RefactoringStatus fatalStatus = new RefactoringStatus.fatal(
307 'Method declaration or reference must be selected to activate this refac toring.');
304 // prepare selected SimpleIdentifier 308 // prepare selected SimpleIdentifier
305 AstNode selectedNode = new NodeLocator.con1(offset).searchWithin(unit); 309 AstNode node = new NodeLocator.con1(offset).searchWithin(unit);
306 if (selectedNode is! SimpleIdentifier) { 310 if (node is! SimpleIdentifier) {
307 return new RefactoringStatus.fatal( 311 return fatalStatus;
308 'Method declaration or reference must be selected to activate this ref actoring.');
309 } 312 }
310 SimpleIdentifier selectedIdentifier = selectedNode as SimpleIdentifier; 313 SimpleIdentifier identifier = node as SimpleIdentifier;
311 // prepare selected ExecutableElement 314 // prepare selected ExecutableElement
312 Element selectedElement = selectedIdentifier.bestElement; 315 Element element = identifier.bestElement;
313 if (selectedElement is! ExecutableElement) { 316 if (element is! ExecutableElement) {
314 return new RefactoringStatus.fatal( 317 return fatalStatus;
315 'Method declaration or reference must be selected to activate this ref actoring.');
316 } 318 }
317 _methodElement = selectedElement as ExecutableElement; 319 _methodElement = element as ExecutableElement;
320 _isAccessor = element is PropertyAccessorElement;
318 _methodFile = _methodElement.source.fullName; 321 _methodFile = _methodElement.source.fullName;
319 _methodUnit = selectedElement.unit; 322 _methodUnit = element.unit;
320 _methodUtils = new CorrectionUtils(_methodUnit); 323 _methodUtils = new CorrectionUtils(_methodUnit);
321 if (selectedElement is MethodElement || 324 // class member
322 selectedElement is PropertyAccessorElement) { 325 bool isClassMember = element.enclosingElement is ClassElement;
323 MethodDeclaration methodDeclaration = 326 if (element is MethodElement || _isAccessor && isClassMember) {
324 _methodElement.node as MethodDeclaration; 327 MethodDeclaration methodDeclaration = element.node;
325 _methodNode = methodDeclaration; 328 _methodNode = methodDeclaration;
326 _methodParameters = methodDeclaration.parameters; 329 _methodParameters = methodDeclaration.parameters;
327 _methodBody = methodDeclaration.body; 330 _methodBody = methodDeclaration.body;
328 // prepare mode 331 // prepare mode
329 isDeclaration = selectedNode == methodDeclaration.name; 332 isDeclaration = node == methodDeclaration.name;
330 deleteSource = isDeclaration; 333 deleteSource = isDeclaration;
331 inlineAll = deleteSource; 334 inlineAll = deleteSource;
335 return new RefactoringStatus();
332 } 336 }
333 if (selectedElement is FunctionElement) { 337 // unit member
334 FunctionDeclaration functionDeclaration = 338 bool isUnitMember = element.enclosingElement is CompilationUnitElement;
335 _methodElement.node as FunctionDeclaration; 339 if (element is FunctionElement || _isAccessor && isUnitMember) {
340 FunctionDeclaration functionDeclaration = element.node;
336 _methodNode = functionDeclaration; 341 _methodNode = functionDeclaration;
337 _methodParameters = functionDeclaration.functionExpression.parameters; 342 _methodParameters = functionDeclaration.functionExpression.parameters;
338 _methodBody = functionDeclaration.functionExpression.body; 343 _methodBody = functionDeclaration.functionExpression.body;
339 // prepare mode 344 // prepare mode
340 isDeclaration = selectedNode == functionDeclaration.name; 345 isDeclaration = node == functionDeclaration.name;
341 deleteSource = isDeclaration; 346 deleteSource = isDeclaration;
342 inlineAll = deleteSource; 347 inlineAll = deleteSource;
348 return new RefactoringStatus();
343 } 349 }
344 // OK 350 // OK
345 return new RefactoringStatus(); 351 return fatalStatus;
346 } 352 }
347 353
348 /** 354 /**
349 * Analyze [_methodBody] to fill [_methodExpressionPart] and 355 * Analyze [_methodBody] to fill [_methodExpressionPart] and
350 * [_methodStatementsPart]. 356 * [_methodStatementsPart].
351 */ 357 */
352 RefactoringStatus _prepareMethodParts() { 358 RefactoringStatus _prepareMethodParts() {
353 RefactoringStatus result = new RefactoringStatus(); 359 RefactoringStatus result = new RefactoringStatus();
354 if (_methodBody is ExpressionFunctionBody) { 360 if (_methodBody is ExpressionFunctionBody) {
355 ExpressionFunctionBody body = _methodBody as ExpressionFunctionBody; 361 ExpressionFunctionBody body = _methodBody as ExpressionFunctionBody;
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 AstNode parent3 = parent2.parent; 464 AstNode parent3 = parent2.parent;
459 return parent3 is VariableDeclarationStatement && 465 return parent3 is VariableDeclarationStatement &&
460 parent3.parent is Block; 466 parent3.parent is Block;
461 } 467 }
462 } 468 }
463 } 469 }
464 // not in block, cannot inline body 470 // not in block, cannot inline body
465 return false; 471 return false;
466 } 472 }
467 473
468 void _inlineMethodInvocation(RefactoringStatus status, Expression methodUsage, 474 void _inlineMethodInvocation(RefactoringStatus status, Expression usage,
469 bool cascaded, Expression target, List<Expression> arguments) { 475 bool cascaded, Expression target, List<Expression> arguments) {
470 // we don't support cascade 476 // we don't support cascade
471 if (cascaded) { 477 if (cascaded) {
472 status.addError( 478 status.addError(
473 'Cannot inline cascade invocation.', 479 'Cannot inline cascade invocation.',
474 new Location.fromNode(methodUsage)); 480 new Location.fromNode(usage));
475 } 481 }
476 // can we inline method body into "methodUsage" block? 482 // can we inline method body into "methodUsage" block?
477 if (_canInlineBody(methodUsage)) { 483 if (_canInlineBody(usage)) {
478 // insert non-return statements 484 // insert non-return statements
479 if (ref._methodStatementsPart != null) { 485 if (ref._methodStatementsPart != null) {
480 // prepare statements source for invocation 486 // prepare statements source for invocation
481 String source = _getMethodSourceForInvocation( 487 String source = _getMethodSourceForInvocation(
482 ref._methodStatementsPart, 488 ref._methodStatementsPart,
483 _refUtils, 489 _refUtils,
484 methodUsage, 490 usage,
485 target, 491 target,
486 arguments); 492 arguments);
487 source = _refUtils.replaceSourceIndent( 493 source = _refUtils.replaceSourceIndent(
488 source, 494 source,
489 ref._methodStatementsPart._prefix, 495 ref._methodStatementsPart._prefix,
490 _refPrefix); 496 _refPrefix);
491 // do insert 497 // do insert
492 SourceRange range = rangeStartLength(_refLineRange, 0); 498 SourceRange range = rangeStartLength(_refLineRange, 0);
493 SourceEdit edit = new SourceEdit.range(range, source); 499 SourceEdit edit = new SourceEdit.range(range, source);
494 ref.change.addEdit(_refFile, edit); 500 ref.change.addEdit(_refFile, edit);
495 } 501 }
496 // replace invocation with return expression 502 // replace invocation with return expression
497 if (ref._methodExpressionPart != null) { 503 if (ref._methodExpressionPart != null) {
498 // prepare expression source for invocation 504 // prepare expression source for invocation
499 String source = _getMethodSourceForInvocation( 505 String source = _getMethodSourceForInvocation(
500 ref._methodExpressionPart, 506 ref._methodExpressionPart,
501 _refUtils, 507 _refUtils,
502 methodUsage, 508 usage,
503 target, 509 target,
504 arguments); 510 arguments);
505 if (getExpressionPrecedence(ref._methodExpression) < 511 if (getExpressionPrecedence(ref._methodExpression) <
506 getExpressionParentPrecedence(methodUsage)) { 512 getExpressionParentPrecedence(usage)) {
507 source = "(${source})"; 513 source = "(${source})";
508 } 514 }
509 // do replace 515 // do replace
510 SourceRange methodUsageRange = rangeNode(methodUsage); 516 SourceRange methodUsageRange = rangeNode(usage);
511 SourceEdit edit = new SourceEdit.range(methodUsageRange, source); 517 SourceEdit edit = new SourceEdit.range(methodUsageRange, source);
512 ref.change.addEdit(_refFile, edit); 518 ref.change.addEdit(_refFile, edit);
513 } else { 519 } else {
514 SourceEdit edit = new SourceEdit.range(_refLineRange, ""); 520 SourceEdit edit = new SourceEdit.range(_refLineRange, "");
515 ref.change.addEdit(_refFile, edit); 521 ref.change.addEdit(_refFile, edit);
516 } 522 }
517 return; 523 return;
518 } 524 }
519 // inline as closure invocation 525 // inline as closure invocation
520 String source; 526 String source;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
552 } else { 558 } else {
553 // cannot inline reference to method: var v = new A().method; 559 // cannot inline reference to method: var v = new A().method;
554 if (ref._methodElement is MethodElement) { 560 if (ref._methodElement is MethodElement) {
555 status.addFatalError( 561 status.addFatalError(
556 'Cannot inline class method reference.', 562 'Cannot inline class method reference.',
557 new Location.fromNode(_node)); 563 new Location.fromNode(_node));
558 return; 564 return;
559 } 565 }
560 // PropertyAccessorElement 566 // PropertyAccessorElement
561 if (ref._methodElement is PropertyAccessorElement) { 567 if (ref._methodElement is PropertyAccessorElement) {
568 Expression usage = _node;
562 Expression target = null; 569 Expression target = null;
563 bool cascade = false; 570 bool cascade = false;
564 if (nodeParent is PrefixedIdentifier) { 571 if (nodeParent is PrefixedIdentifier) {
565 PrefixedIdentifier propertyAccess = nodeParent; 572 PrefixedIdentifier propertyAccess = nodeParent;
573 usage = propertyAccess;
566 target = propertyAccess.prefix; 574 target = propertyAccess.prefix;
567 cascade = false; 575 cascade = false;
568 } 576 }
569 if (nodeParent is PropertyAccess) { 577 if (nodeParent is PropertyAccess) {
570 PropertyAccess propertyAccess = nodeParent; 578 PropertyAccess propertyAccess = nodeParent;
579 usage = propertyAccess;
571 target = propertyAccess.realTarget; 580 target = propertyAccess.realTarget;
572 cascade = propertyAccess.isCascaded; 581 cascade = propertyAccess.isCascaded;
573 } 582 }
574 // prepare arguments 583 // prepare arguments
575 List<Expression> arguments = []; 584 List<Expression> arguments = [];
576 if ((_node as SimpleIdentifier).inSetterContext()) { 585 if ((_node as SimpleIdentifier).inSetterContext()) {
577 arguments.add( 586 AssignmentExpression assignment;
578 (nodeParent.parent as AssignmentExpression).rightHandSide); 587 if (nodeParent is AssignmentExpression) {
588 assignment = nodeParent;
589 } else {
590 assignment = nodeParent.parent;
Brian Wilkerson 2014/09/12 22:42:31 Are two levels always enough? Consider using getAn
scheglov 2014/09/14 03:17:39 Ah, yes. Thank you!
591 }
592 arguments.add(assignment.rightHandSide);
579 } 593 }
580 // inline body 594 // inline body
581 _inlineMethodInvocation( 595 _inlineMethodInvocation(status, usage, cascade, target, arguments);
582 status,
583 nodeParent as Expression,
584 cascade,
585 target,
586 arguments);
587 return; 596 return;
588 } 597 }
589 // not invocation, just reference to function 598 // not invocation, just reference to function
590 String source; 599 String source;
591 { 600 {
592 source = ref._methodUtils.getRangeText( 601 source = ref._methodUtils.getRangeText(
593 rangeStartEnd(ref._methodParameters.leftParenthesis, ref._methodNode )); 602 rangeStartEnd(ref._methodParameters.leftParenthesis, ref._methodNode ));
594 String methodPrefix = 603 String methodPrefix =
595 ref._methodUtils.getLinePrefix(ref._methodNode.offset); 604 ref._methodUtils.getLinePrefix(ref._methodNode.offset);
596 source = 605 source =
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
795 } 804 }
796 805
797 void _addVariable(SimpleIdentifier node) { 806 void _addVariable(SimpleIdentifier node) {
798 VariableElement variableElement = getLocalVariableElement(node); 807 VariableElement variableElement = getLocalVariableElement(node);
799 if (variableElement != null) { 808 if (variableElement != null) {
800 SourceRange nodeRange = rangeNode(node); 809 SourceRange nodeRange = rangeNode(node);
801 result.addVariable(variableElement, nodeRange); 810 result.addVariable(variableElement, nodeRange);
802 } 811 }
803 } 812 }
804 } 813 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698