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

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

Issue 515733002: 'Inline Local' refactoring. (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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library services.src.refactoring.inline_local;
6
7 import 'dart:async';
8
9 import 'package:analysis_server/src/protocol.dart' hide Element;
10 import 'package:analysis_server/src/services/correction/status.dart';
11 import 'package:analysis_server/src/services/correction/util.dart';
12 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
13 import 'package:analysis_server/src/services/refactoring/refactoring_internal.da rt';
14 import 'package:analysis_server/src/services/search/search_engine.dart';
15 import 'package:analyzer/src/generated/ast.dart';
16 import 'package:analyzer/src/generated/element.dart';
17 import 'package:analyzer/src/generated/java_core.dart';
18 import 'package:analyzer/src/generated/scanner.dart';
19 import 'package:analyzer/src/generated/source.dart';
20
21
22 const String _TOKEN_SEPARATOR = "\uFFFF";
23
24
25 /**
26 * [InlineLocalRefactoring] implementation.
27 */
28 class InlineLocalRefactoringImpl extends RefactoringImpl implements
29 InlineLocalRefactoring {
30 final SearchEngine searchEngine;
31 final CompilationUnit unit;
32 final LocalVariableElement element;
33 String file;
34 CorrectionUtils utils;
35
36 VariableDeclaration _variableNode;
37 List<SearchMatch> _references;
38
39 InlineLocalRefactoringImpl(this.searchEngine, this.unit, this.element) {
40 file = unit.element.source.fullName;
41 utils = new CorrectionUtils(unit);
42 }
43
44 @override
45 String get refactoringName => 'Inline Local Variable';
46
47 @override
48 int get referenceCount {
49 return _references.length;
50 }
51
52 @override
53 Future<RefactoringStatus> checkFinalConditions() {
54 RefactoringStatus result = new RefactoringStatus();
55 return new Future.value(result);
56 }
57
58 @override
59 Future<RefactoringStatus> checkInitialConditions() {
60 RefactoringStatus result = new RefactoringStatus();
61 // prepare variable
62 {
63 AstNode elementNode = utils.findNode(element.nameOffset);
64 _variableNode = elementNode != null ?
65 elementNode.getAncestor((node) => node is VariableDeclaration) :
66 null;
67 }
68 // should be normal variable declaration statement
69 if (_variableNode.parent is! VariableDeclarationList ||
70 _variableNode.parent.parent is! VariableDeclarationStatement ||
71 _variableNode.parent.parent.parent is! Block) {
72 result = new RefactoringStatus.fatal(
73 'Local variable declared in '
74 'statement should be selected to activate this refactoring.');
75 return new Future.value(result);
76 }
77 // should have initializer at declaration
78 if (_variableNode.initializer == null) {
79 String message = format(
80 "Local variable '{0}' is not initialized at declaration.",
81 element.displayName);
82 result =
83 new RefactoringStatus.fatal(message, new Location.fromNode(_variableNo de));
84 return new Future.value(result);
85 }
86 // prepare references
87 return searchEngine.searchReferences(element).then((references) {
88 this._references = references;
89 // should not have assignments
90 for (SearchMatch reference in _references) {
91 if (reference.kind != MatchKind.READ) {
92 String message = format(
93 "Local variable '{0}' is assigned more than once.",
94 [element.displayName]);
95 return new RefactoringStatus.fatal(
96 message,
97 new Location.fromMatch(reference));
98 }
99 }
100 // done
101 return result;
102 });
103 }
104
105 @override
106 Future<SourceChange> createChange() {
107 SourceChange change = new SourceChange(refactoringName);
108 // remove declaration
109 {
110 Statement declarationStatement =
111 _variableNode.getAncestor((node) => node is VariableDeclarationStateme nt);
112 SourceRange range = utils.getLinesRangeStatements([declarationStatement]);
113 change.addEdit(file, new SourceEdit.range(range, ''));
114 }
115 // prepare initializer
116 Expression initializer = _variableNode.initializer;
117 String initializerSource = utils.getNodeText(initializer);
118 int initializerPrecedence = getExpressionPrecedence(initializer);
119 // replace references
120 for (SearchMatch reference in _references) {
121 SourceRange range = reference.sourceRange;
122 String sourceForReference =
123 _getSourceForReference(range, initializerSource, initializerPrecedence );
124 change.addEdit(file, new SourceEdit.range(range, sourceForReference));
125 }
126 // done
127 return new Future.value(change);
128 }
129
130 @override
131 bool requiresPreview() => false;
132
133 /**
134 * Returns the source which should be used to replace the reference with the
135 * given [SourceRange].
136 *
137 * [range] - the [SourceRange] of the reference.
138 * [source] - the source of the initializer, to be inserted at [range].
139 * [precedence] - the precedence of the initializer [source].
140 */
141 String _getSourceForReference(SourceRange range, String source,
142 int precedence) {
143 int offset = range.offset;
144 AstNode node = utils.findNode(offset);
145 AstNode parent = node.parent;
146 if (_isIdentifierStringInterpolation(parent)) {
147 return '{${source}}';
148 }
149 if (precedence < getExpressionParentPrecedence(node)) {
150 return '(${source})';
151 }
152 return source;
153 }
154
155 /**
156 * Checks if the given node is a string interpolation in form `$name`.
157 */
158 bool _isIdentifierStringInterpolation(AstNode parent) {
159 if (parent is InterpolationExpression) {
160 InterpolationExpression element = parent;
161 return element.beginToken.type ==
162 TokenType.STRING_INTERPOLATION_IDENTIFIER;
163 }
164 return false;
165 }
166 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698