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_services/lib/src/correction/util.dart

Issue 437323004: Port and test more assists. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix for review comment. Created 6 years, 4 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 // This code was auto-generated, is not intended to be edited, and is subject to 5 // This code was auto-generated, is not intended to be edited, and is subject to
6 // significant change. Please see the README file for more information. 6 // significant change. Please see the README file for more information.
7 7
8 library services.src.correction.util; 8 library services.src.correction.util;
9 9
10 import 'package:analysis_services/correction/change.dart';
10 import 'package:analysis_services/src/correction/source_range.dart'; 11 import 'package:analysis_services/src/correction/source_range.dart';
11 import 'package:analysis_services/src/correction/strings.dart'; 12 import 'package:analysis_services/src/correction/strings.dart';
12 import 'package:analyzer/src/generated/ast.dart'; 13 import 'package:analyzer/src/generated/ast.dart';
13 import 'package:analyzer/src/generated/element.dart'; 14 import 'package:analyzer/src/generated/element.dart';
14 import 'package:analyzer/src/generated/engine.dart'; 15 import 'package:analyzer/src/generated/engine.dart';
15 import 'package:analyzer/src/generated/resolver.dart'; 16 import 'package:analyzer/src/generated/resolver.dart';
17 import 'package:analyzer/src/generated/scanner.dart';
16 import 'package:analyzer/src/generated/source.dart'; 18 import 'package:analyzer/src/generated/source.dart';
17 19
18 20
19 String getDefaultValueCode(DartType type) { 21 String getDefaultValueCode(DartType type) {
20 if (type != null) { 22 if (type != null) {
21 String typeName = type.displayName; 23 String typeName = type.displayName;
22 if (typeName == "bool") { 24 if (typeName == "bool") {
23 return "false"; 25 return "false";
24 } 26 }
25 if (typeName == "int") { 27 if (typeName == "int") {
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 if (parent is PropertyAccess) { 138 if (parent is PropertyAccess) {
137 PropertyAccess access = parent; 139 PropertyAccess access = parent;
138 if (identical(access.propertyName, node)) { 140 if (identical(access.propertyName, node)) {
139 return access.realTarget; 141 return access.realTarget;
140 } 142 }
141 } 143 }
142 return null; 144 return null;
143 } 145 }
144 146
145 /** 147 /**
148 * Returns the given [Statement] if not a [Block], or the first child
149 * [Statement] if a [Block], or `null` if more than one child.
150 */
151 Statement getSingleStatement(Statement statement) {
152 if (statement is Block) {
153 List<Statement> blockStatements = statement.statements;
154 if (blockStatements.length != 1) {
155 return null;
156 }
157 return blockStatements[0];
158 }
159 return statement;
160 }
161
162 /**
146 * Returns the [String] content of the given [Source]. 163 * Returns the [String] content of the given [Source].
147 */ 164 */
148 String getSourceContent(AnalysisContext context, Source source) { 165 String getSourceContent(AnalysisContext context, Source source) {
149 return context.getContents(source).data; 166 return context.getContents(source).data;
150 } 167 }
151 168
169
170 /**
171 * Returns the given [Statement] if not a [Block], or all the children
172 * [Statement]s if a [Block].
173 */
174 List<Statement> getStatements(Statement statement) {
175 if (statement is Block) {
176 return statement.statements;
177 }
178 return [statement];
179 }
180
181
152 class CorrectionUtils { 182 class CorrectionUtils {
153 final CompilationUnit unit; 183 final CompilationUnit unit;
154 184
155 LibraryElement _library; 185 LibraryElement _library;
156 String _buffer; 186 String _buffer;
157 String _endOfLine; 187 String _endOfLine;
158 188
159 CorrectionUtils(this.unit) { 189 CorrectionUtils(this.unit) {
160 CompilationUnitElement unitElement = unit.element; 190 CompilationUnitElement unitElement = unit.element;
161 this._library = unitElement.library; 191 this._library = unitElement.library;
162 this._buffer = unitElement.context.getContents(unitElement.source).data; 192 this._buffer = unitElement.context.getContents(unitElement.source).data;
163 } 193 }
164 194
165 /** 195 /**
166 * Returns the EOL to use for this [CompilationUnit]. 196 * Returns the EOL to use for this [CompilationUnit].
167 */ 197 */
168 String get endOfLine { 198 String get endOfLine {
169 if (_endOfLine == null) { 199 if (_endOfLine == null) {
170 if (_buffer.contains("\r\n")) { 200 if (_buffer.contains("\r\n")) {
171 _endOfLine = "\r\n"; 201 _endOfLine = "\r\n";
172 } else { 202 } else {
173 _endOfLine = "\n"; 203 _endOfLine = "\n";
174 } 204 }
175 } 205 }
176 return _endOfLine; 206 return _endOfLine;
177 } 207 }
178 208
179 /** 209 /**
210 * Returns an [Edit] that changes indentation of the source of the given
211 * [SourceRange] from [oldIndent] to [newIndent], keeping indentation of lines
212 * relative to each other.
213 */
214 Edit createIndentEdit(SourceRange range, String oldIndent, String newIndent) {
215 String newSource = getIndentSource(range, oldIndent, newIndent);
216 return new Edit(range.offset, range.length, newSource);
217 }
218
219 /**
180 * Returns the actual type source of the given [Expression], may be `null` 220 * Returns the actual type source of the given [Expression], may be `null`
181 * if can not be resolved, should be treated as the `dynamic` type. 221 * if can not be resolved, should be treated as the `dynamic` type.
182 */ 222 */
183 String getExpressionTypeSource(Expression expression) { 223 String getExpressionTypeSource(Expression expression) {
184 if (expression == null) { 224 if (expression == null) {
185 return null; 225 return null;
186 } 226 }
187 DartType type = expression.bestType; 227 DartType type = expression.bestType;
188 if (type.isDynamic) { 228 if (type.isDynamic) {
189 return null; 229 return null;
190 } 230 }
191 return getTypeSource(type); 231 return getTypeSource(type);
192 } 232 }
193 233
194 /** 234 /**
195 * Returns the indentation with the given level. 235 * Returns the indentation with the given level.
196 */ 236 */
197 String getIndent(int level) => repeat(' ', level); 237 String getIndent(int level) => repeat(' ', level);
198 238
199 /** 239 /**
240 * Returns the source of the given [SourceRange] with indentation changed
241 * from [oldIndent] to [newIndent], keeping indentation of lines relative
242 * to each other.
243 */
244 String getIndentSource(SourceRange range, String oldIndent,
245 String newIndent) {
246 String oldSource = getText3(range);
247 return getIndentSource3(oldSource, oldIndent, newIndent);
248 }
249
250 /**
251 * Indents given source left or right.
252 */
253 String getIndentSource2(String source, bool right) {
254 // TODO(scheglov) rename
255 StringBuffer sb = new StringBuffer();
256 String indent = getIndent(1);
257 String eol = endOfLine;
258 List<String> lines = source.split(eol);
259 for (int i = 0; i < lines.length; i++) {
260 String line = lines[i];
261 // last line, stop if empty
262 if (i == lines.length - 1 && isEmpty(line)) {
263 break;
264 }
265 // update line
266 if (right) {
267 line = "${indent}${line}";
268 } else {
269 line = removeStart(line, indent);
270 }
271 // append line
272 sb.write(line);
273 sb.write(eol);
274 }
275 return sb.toString();
276 }
277
278 /**
279 * Returns the source with indentation changed from [oldIndent] to
280 * [newIndent], keeping indentation of lines relative to each other.
281 */
282 String getIndentSource3(String source, String oldIndent, String newIndent) {
283 // TODO(scheglov) rename
284 // prepare STRING token ranges
285 List<SourceRange> lineRanges = [];
286 {
287 var token = unit.beginToken;
288 while (token != null && token.type != TokenType.EOF) {
289 if (token.type == TokenType.STRING) {
290 lineRanges.add(rangeToken(token));
291 }
292 token = token.next;
293 }
294 }
295 // re-indent lines
296 StringBuffer sb = new StringBuffer();
297 String eol = endOfLine;
298 List<String> lines = source.split(eol);
299 int lineOffset = 0;
300 for (int i = 0; i < lines.length; i++) {
301 String line = lines[i];
302 // last line, stop if empty
303 if (i == lines.length - 1 && isEmpty(line)) {
304 break;
305 }
306 // check if "offset" is in one of the String ranges
307 bool inString = false;
308 for (SourceRange lineRange in lineRanges) {
309 if (lineOffset > lineRange.offset && lineOffset < lineRange.end) {
310 inString = true;
311 }
312 if (lineOffset > lineRange.end) {
313 break;
314 }
315 }
316 lineOffset += line.length + eol.length;
317 // update line indent
318 if (!inString) {
319 line = "${newIndent}${removeStart(line, oldIndent)}";
320 }
321 // append line
322 sb.write(line);
323 sb.write(eol);
324 }
325 return sb.toString();
326 }
327
328 /**
200 * Returns a [InsertDesc] describing where to insert a new library-related 329 * Returns a [InsertDesc] describing where to insert a new library-related
201 * directive. 330 * directive.
202 */ 331 */
203 CorrectionUtils_InsertDesc getInsertDescImport() { 332 CorrectionUtils_InsertDesc getInsertDescImport() {
204 // analyze directives 333 // analyze directives
205 Directive prevDirective = null; 334 Directive prevDirective = null;
206 for (Directive directive in unit.directives) { 335 for (Directive directive in unit.directives) {
207 if (directive is LibraryDirective || 336 if (directive is LibraryDirective ||
208 directive is ImportDirective || 337 directive is ImportDirective ||
209 directive is ExportDirective) { 338 directive is ExportDirective) {
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
426 int startOffset = range.offset; 555 int startOffset = range.offset;
427 int startLineOffset = getLineContentStart(startOffset); 556 int startLineOffset = getLineContentStart(startOffset);
428 // end 557 // end
429 int endOffset = range.end; 558 int endOffset = range.end;
430 int afterEndLineOffset = getLineContentEnd(endOffset); 559 int afterEndLineOffset = getLineContentEnd(endOffset);
431 // range 560 // range
432 return rangeStartEnd(startLineOffset, afterEndLineOffset); 561 return rangeStartEnd(startLineOffset, afterEndLineOffset);
433 } 562 }
434 563
435 /** 564 /**
565 * Returns a [SourceRange] that covers all the given [Statement]s.
566 */
567 SourceRange getLinesRangeStatements(List<Statement> statements) {
568 SourceRange range = rangeNodes(statements);
569 return getLinesRange(range);
570 }
571
572 /**
436 * Returns the line prefix consisting of spaces and tabs on the left from the given 573 * Returns the line prefix consisting of spaces and tabs on the left from the given
437 * [AstNode]. 574 * [AstNode].
438 */ 575 */
439 String getNodePrefix(AstNode node) { 576 String getNodePrefix(AstNode node) {
440 int offset = node.offset; 577 int offset = node.offset;
441 // function literal is special, it uses offset of enclosing line 578 // function literal is special, it uses offset of enclosing line
442 if (node is FunctionExpression) { 579 if (node is FunctionExpression) {
443 return getLinePrefix(offset); 580 return getLinePrefix(offset);
444 } 581 }
445 // use just prefix directly before node 582 // use just prefix directly before node
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 sb.write(getTypeSource(argument)); 705 sb.write(getTypeSource(argument));
569 } 706 }
570 sb.write(">"); 707 sb.write(">");
571 } 708 }
572 } 709 }
573 // done 710 // done
574 return sb.toString(); 711 return sb.toString();
575 } 712 }
576 713
577 /** 714 /**
715 * @return the source of the inverted condition for the given logical expressi on.
716 */
717 String invertCondition(Expression expression) =>
718 _invertCondition0(expression)._source;
719
720 /**
578 * @return the [ImportElement] used to import given [Element] into [library]. 721 * @return the [ImportElement] used to import given [Element] into [library].
579 * May be `null` if was not imported, i.e. declared in the same librar y. 722 * May be `null` if was not imported, i.e. declared in the same librar y.
580 */ 723 */
581 ImportElement _getImportElement(Element element) { 724 ImportElement _getImportElement(Element element) {
582 for (ImportElement imp in _library.imports) { 725 for (ImportElement imp in _library.imports) {
583 Map<String, Element> definedNames = getImportNamespace(imp); 726 Map<String, Element> definedNames = getImportNamespace(imp);
584 if (definedNames.containsValue(element)) { 727 if (definedNames.containsValue(element)) {
585 return imp; 728 return imp;
586 } 729 }
587 } 730 }
588 return null; 731 return null;
589 } 732 }
733
734 /**
735 * @return the [InvertedCondition] for the given logical expression.
736 */
737 _InvertedCondition _invertCondition0(Expression expression) {
738 if (expression is BooleanLiteral) {
739 BooleanLiteral literal = expression;
740 if (literal.value) {
741 return _InvertedCondition._simple("false");
742 } else {
743 return _InvertedCondition._simple("true");
744 }
745 }
746 if (expression is BinaryExpression) {
747 BinaryExpression binary = expression;
748 TokenType operator = binary.operator.type;
749 Expression le = binary.leftOperand;
750 Expression re = binary.rightOperand;
751 _InvertedCondition ls = _invertCondition0(le);
752 _InvertedCondition rs = _invertCondition0(re);
753 if (operator == TokenType.LT) {
754 return _InvertedCondition._binary2(ls, " >= ", rs);
755 }
756 if (operator == TokenType.GT) {
757 return _InvertedCondition._binary2(ls, " <= ", rs);
758 }
759 if (operator == TokenType.LT_EQ) {
760 return _InvertedCondition._binary2(ls, " > ", rs);
761 }
762 if (operator == TokenType.GT_EQ) {
763 return _InvertedCondition._binary2(ls, " < ", rs);
764 }
765 if (operator == TokenType.EQ_EQ) {
766 return _InvertedCondition._binary2(ls, " != ", rs);
767 }
768 if (operator == TokenType.BANG_EQ) {
769 return _InvertedCondition._binary2(ls, " == ", rs);
770 }
771 if (operator == TokenType.AMPERSAND_AMPERSAND) {
772 return _InvertedCondition._binary(
773 TokenType.BAR_BAR.precedence,
774 ls,
775 " || ",
776 rs);
777 }
778 if (operator == TokenType.BAR_BAR) {
779 return _InvertedCondition._binary(
780 TokenType.AMPERSAND_AMPERSAND.precedence,
781 ls,
782 " && ",
783 rs);
784 }
785 }
786 if (expression is IsExpression) {
787 IsExpression isExpression = expression;
788 String expressionSource = getText(isExpression.expression);
789 String typeSource = getText(isExpression.type);
790 if (isExpression.notOperator == null) {
791 return _InvertedCondition._simple(
792 "${expressionSource} is! ${typeSource}");
793 } else {
794 return _InvertedCondition._simple(
795 "${expressionSource} is ${typeSource}");
796 }
797 }
798 if (expression is PrefixExpression) {
799 PrefixExpression prefixExpression = expression;
800 TokenType operator = prefixExpression.operator.type;
801 if (operator == TokenType.BANG) {
802 Expression operand = prefixExpression.operand;
803 while (operand is ParenthesizedExpression) {
804 ParenthesizedExpression pe = operand as ParenthesizedExpression;
805 operand = pe.expression;
806 }
807 return _InvertedCondition._simple(getText(operand));
808 }
809 }
810 if (expression is ParenthesizedExpression) {
811 ParenthesizedExpression pe = expression;
812 Expression innerExpresion = pe.expression;
813 while (innerExpresion is ParenthesizedExpression) {
814 innerExpresion = (innerExpresion as ParenthesizedExpression).expression;
815 }
816 return _invertCondition0(innerExpresion);
817 }
818 DartType type = expression.bestType;
819 if (type.displayName == "bool") {
820 return _InvertedCondition._simple("!${getText(expression)}");
821 }
822 return _InvertedCondition._simple(getText(expression));
823 }
590 } 824 }
591 825
592 826
593 /** 827 /**
594 * Describes where to insert new directive or top-level declaration. 828 * Describes where to insert new directive or top-level declaration.
595 */ 829 */
596 class CorrectionUtils_InsertDesc { 830 class CorrectionUtils_InsertDesc {
597 int offset = 0; 831 int offset = 0;
598 String prefix = ""; 832 String prefix = "";
599 String suffix = ""; 833 String suffix = "";
600 } 834 }
835
836
837 /**
838 * A container with a source and its precedence.
839 */
840 class _InvertedCondition {
841 final int _precedence;
842
843 final String _source;
844
845 _InvertedCondition(this._precedence, this._source);
846
847 static _InvertedCondition _binary(int precedence, _InvertedCondition left,
848 String operation, _InvertedCondition right) {
849 String src =
850 _parenthesizeIfRequired(left, precedence) +
851 operation +
852 _parenthesizeIfRequired(right, precedence);
853 return new _InvertedCondition(precedence, src);
854 }
855
856 static _InvertedCondition _binary2(_InvertedCondition left, String operation,
857 _InvertedCondition right) {
858 // TODO(scheglov) conside merging with "_binary()" after testing
859 return new _InvertedCondition(
860 1 << 20,
861 "${left._source}${operation}${right._source}");
862 }
863
864 /**
865 * Adds enclosing parenthesis if the precedence of the [_InvertedCondition] if l ess than the
866 * precedence of the expression we are going it to use in.
867 */
868 static String _parenthesizeIfRequired(_InvertedCondition expr,
869 int newOperatorPrecedence) {
870 if (expr._precedence < newOperatorPrecedence) {
871 return "(${expr._source})";
872 }
873 return expr._source;
874 }
875
876
877 static _InvertedCondition _simple(String source) =>
878 new _InvertedCondition(2147483647, source);
879 }
OLDNEW
« no previous file with comments | « pkg/analysis_services/lib/src/correction/assist.dart ('k') | pkg/analysis_services/test/correction/assist_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698