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

Side by Side Diff: pkg/analysis_services/lib/src/correction/util.dart

Issue 484733003: Import analysis_services.dart into analysis_server.dart. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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
(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.correction.util;
6
7 import 'package:analysis_services/correction/change.dart';
8 import 'package:analysis_services/src/correction/source_range.dart';
9 import 'package:analysis_services/src/correction/strings.dart';
10 import 'package:analyzer/src/generated/ast.dart';
11 import 'package:analyzer/src/generated/element.dart';
12 import 'package:analyzer/src/generated/engine.dart';
13 import 'package:analyzer/src/generated/resolver.dart';
14 import 'package:analyzer/src/generated/scanner.dart';
15 import 'package:analyzer/src/generated/source.dart';
16
17
18 /**
19 * TODO(scheglov) replace with nodes once there will be [CompilationUnit#getComm ents].
20 *
21 * Returns [SourceRange]s of all comments in [unit].
22 */
23 List<SourceRange> getCommentRanges(CompilationUnit unit) {
24 List<SourceRange> ranges = <SourceRange>[];
25 Token token = unit.beginToken;
26 while (token != null && token.type != TokenType.EOF) {
27 Token commentToken = token.precedingComments;
28 while (commentToken != null) {
29 ranges.add(rangeToken(commentToken));
30 commentToken = commentToken.next;
31 }
32 token = token.next;
33 }
34 return ranges;
35 }
36
37
38 String getDefaultValueCode(DartType type) {
39 if (type != null) {
40 String typeName = type.displayName;
41 if (typeName == "bool") {
42 return "false";
43 }
44 if (typeName == "int") {
45 return "0";
46 }
47 if (typeName == "double") {
48 return "0.0";
49 }
50 if (typeName == "String") {
51 return "''";
52 }
53 }
54 // no better guess
55 return "null";
56 }
57
58
59 /**
60 * Return the name of the [Element] kind.
61 */
62 String getElementKindName(Element element) {
63 return element.kind.displayName;
64 }
65
66
67 /**
68 * Returns the name to display in the UI for the given [Element].
69 */
70 String getElementQualifiedName(Element element) {
71 ElementKind kind = element.kind;
72 if (kind == ElementKind.FIELD || kind == ElementKind.METHOD) {
73 return '${element.enclosingElement.displayName}.${element.displayName}';
74 } else {
75 return element.displayName;
76 }
77 }
78
79
80 /**
81 * @return the [ExecutableElement] of the enclosing executable [AstNode].
82 */
83 ExecutableElement getEnclosingExecutableElement(AstNode node) {
84 while (node != null) {
85 if (node is FunctionDeclaration) {
86 return node.element;
87 }
88 if (node is ConstructorDeclaration) {
89 return node.element;
90 }
91 if (node is MethodDeclaration) {
92 return node.element;
93 }
94 node = node.parent;
95 }
96 return null;
97 }
98
99 /**
100 * Returns a namespace of the given [ExportElement].
101 */
102 Map<String, Element> getExportNamespaceForDirective(ExportElement exp) {
103 Namespace namespace =
104 new NamespaceBuilder().createExportNamespaceForDirective(exp);
105 return namespace.definedNames;
106 }
107
108
109 /**
110 * Returns a export namespace of the given [LibraryElement].
111 */
112 Map<String, Element> getExportNamespaceForLibrary(LibraryElement library) {
113 Namespace namespace =
114 new NamespaceBuilder().createExportNamespaceForLibrary(library);
115 return namespace.definedNames;
116 }
117
118 /**
119 * Returns an [Element] exported from the given [LibraryElement].
120 */
121 Element getExportedElement(LibraryElement library, String name) {
122 if (library == null) {
123 return null;
124 }
125 return getExportNamespaceForLibrary(library)[name];
126 }
127
128 /**
129 * Returns [getExpressionPrecedence] for the parent of [node],
130 * or `0` if the parent node is [ParenthesizedExpression].
131 *
132 * The reason is that `(expr)` is always executed after `expr`.
133 */
134 int getExpressionParentPrecedence(AstNode node) {
135 AstNode parent = node.parent;
136 if (parent is ParenthesizedExpression) {
137 return 0;
138 }
139 return getExpressionPrecedence(parent);
140 }
141
142 /**
143 * Returns the precedence of [node] it is an [Expression], negative otherwise.
144 */
145 int getExpressionPrecedence(AstNode node) {
146 if (node is Expression) {
147 return node.precedence;
148 }
149 return -1000;
150 }
151
152 /**
153 * Returns the namespace of the given [ImportElement].
154 */
155 Map<String, Element> getImportNamespace(ImportElement imp) {
156 NamespaceBuilder builder = new NamespaceBuilder();
157 Namespace namespace = builder.createImportNamespaceForDirective(imp);
158 return namespace.definedNames;
159 }
160
161
162 /**
163 * If given [AstNode] is name of qualified property extraction, returns target f rom which
164 * this property is extracted. Otherwise `null`.
165 */
166 Expression getQualifiedPropertyTarget(AstNode node) {
167 AstNode parent = node.parent;
168 if (parent is PrefixedIdentifier) {
169 PrefixedIdentifier prefixed = parent;
170 if (prefixed.identifier == node) {
171 return parent.prefix;
172 }
173 }
174 if (parent is PropertyAccess) {
175 PropertyAccess access = parent;
176 if (access.propertyName == node) {
177 return access.realTarget;
178 }
179 }
180 return null;
181 }
182
183
184 /**
185 * Returns the given [Statement] if not a [Block], or the first child
186 * [Statement] if a [Block], or `null` if more than one child.
187 */
188 Statement getSingleStatement(Statement statement) {
189 if (statement is Block) {
190 List<Statement> blockStatements = statement.statements;
191 if (blockStatements.length != 1) {
192 return null;
193 }
194 return blockStatements[0];
195 }
196 return statement;
197 }
198
199
200 /**
201 * Returns the [String] content of the given [Source].
202 */
203 String getSourceContent(AnalysisContext context, Source source) {
204 return context.getContents(source).data;
205 }
206
207
208 /**
209 * Returns the given [Statement] if not a [Block], or all the children
210 * [Statement]s if a [Block].
211 */
212 List<Statement> getStatements(Statement statement) {
213 if (statement is Block) {
214 return statement.statements;
215 }
216 return [statement];
217 }
218
219
220 /**
221 * Checks if the given [Element]'s display name equals to the given name.
222 */
223 bool hasDisplayName(Element element, String name) {
224 if (element == null) {
225 return false;
226 }
227 return element.displayName == name;
228 }
229
230
231 class CorrectionUtils {
232 final CompilationUnit unit;
233
234 LibraryElement _library;
235 String _buffer;
236 String _endOfLine;
237
238 CorrectionUtils(this.unit) {
239 CompilationUnitElement unitElement = unit.element;
240 this._library = unitElement.library;
241 this._buffer = unitElement.context.getContents(unitElement.source).data;
242 }
243
244 /**
245 * Returns the EOL to use for this [CompilationUnit].
246 */
247 String get endOfLine {
248 if (_endOfLine == null) {
249 if (_buffer.contains("\r\n")) {
250 _endOfLine = "\r\n";
251 } else {
252 _endOfLine = "\n";
253 }
254 }
255 return _endOfLine;
256 }
257
258 /**
259 * Returns an [Edit] that changes indentation of the source of the given
260 * [SourceRange] from [oldIndent] to [newIndent], keeping indentation of lines
261 * relative to each other.
262 */
263 Edit createIndentEdit(SourceRange range, String oldIndent, String newIndent) {
264 String newSource = replaceSourceRangeIndent(range, oldIndent, newIndent);
265 return new Edit(range.offset, range.length, newSource);
266 }
267
268 /**
269 * Returns the actual type source of the given [Expression], may be `null`
270 * if can not be resolved, should be treated as the `dynamic` type.
271 */
272 String getExpressionTypeSource(Expression expression) {
273 if (expression == null) {
274 return null;
275 }
276 DartType type = expression.bestType;
277 if (type.isDynamic) {
278 return null;
279 }
280 return getTypeSource(type);
281 }
282
283 /**
284 * Returns the indentation with the given level.
285 */
286 String getIndent(int level) => repeat(' ', level);
287
288 /**
289 * Returns a [InsertDesc] describing where to insert a new library-related
290 * directive.
291 */
292 CorrectionUtils_InsertDesc getInsertDescImport() {
293 // analyze directives
294 Directive prevDirective = null;
295 for (Directive directive in unit.directives) {
296 if (directive is LibraryDirective ||
297 directive is ImportDirective ||
298 directive is ExportDirective) {
299 prevDirective = directive;
300 }
301 }
302 // insert after last library-related directive
303 if (prevDirective != null) {
304 CorrectionUtils_InsertDesc result = new CorrectionUtils_InsertDesc();
305 result.offset = prevDirective.end;
306 String eol = endOfLine;
307 if (prevDirective is LibraryDirective) {
308 result.prefix = "${eol}${eol}";
309 } else {
310 result.prefix = eol;
311 }
312 return result;
313 }
314 // no directives, use "top" location
315 return getInsertDescTop();
316 }
317
318 /**
319 * Returns a [InsertDesc] describing where to insert a new 'part' directive.
320 */
321 CorrectionUtils_InsertDesc getInsertDescPart() {
322 // analyze directives
323 Directive prevDirective = null;
324 for (Directive directive in unit.directives) {
325 prevDirective = directive;
326 }
327 // insert after last directive
328 if (prevDirective != null) {
329 CorrectionUtils_InsertDesc result = new CorrectionUtils_InsertDesc();
330 result.offset = prevDirective.end;
331 String eol = endOfLine;
332 if (prevDirective is PartDirective) {
333 result.prefix = eol;
334 } else {
335 result.prefix = "${eol}${eol}";
336 }
337 return result;
338 }
339 // no directives, use "top" location
340 return getInsertDescTop();
341 }
342
343 /**
344 * Returns a [InsertDesc] describing where to insert a new directive or a
345 * top-level declaration at the top of the file.
346 */
347 CorrectionUtils_InsertDesc getInsertDescTop() {
348 // skip leading line comments
349 int offset = 0;
350 bool insertEmptyLineBefore = false;
351 bool insertEmptyLineAfter = false;
352 String source = _buffer;
353 // skip hash-bang
354 if (offset < source.length - 2) {
355 String linePrefix = getText(offset, 2);
356 if (linePrefix == "#!") {
357 insertEmptyLineBefore = true;
358 offset = getLineNext(offset);
359 // skip empty lines to first line comment
360 int emptyOffset = offset;
361 while (emptyOffset < source.length - 2) {
362 int nextLineOffset = getLineNext(emptyOffset);
363 String line = source.substring(emptyOffset, nextLineOffset);
364 if (line.trim().isEmpty) {
365 emptyOffset = nextLineOffset;
366 continue;
367 } else if (line.startsWith("//")) {
368 offset = emptyOffset;
369 break;
370 } else {
371 break;
372 }
373 }
374 }
375 }
376 // skip line comments
377 while (offset < source.length - 2) {
378 String linePrefix = getText(offset, 2);
379 if (linePrefix == "//") {
380 insertEmptyLineBefore = true;
381 offset = getLineNext(offset);
382 } else {
383 break;
384 }
385 }
386 // determine if empty line is required after
387 int nextLineOffset = getLineNext(offset);
388 String insertLine = source.substring(offset, nextLineOffset);
389 if (!insertLine.trim().isEmpty) {
390 insertEmptyLineAfter = true;
391 }
392 // fill InsertDesc
393 CorrectionUtils_InsertDesc desc = new CorrectionUtils_InsertDesc();
394 desc.offset = offset;
395 if (insertEmptyLineBefore) {
396 desc.prefix = endOfLine;
397 }
398 if (insertEmptyLineAfter) {
399 desc.suffix = endOfLine;
400 }
401 return desc;
402 }
403
404 /**
405 * Skips whitespace characters and single EOL on the right from [index].
406 *
407 * If [index] the end of a statement or method, then in the most cases it is
408 * a start of the next line.
409 */
410 int getLineContentEnd(int index) {
411 int length = _buffer.length;
412 // skip whitespace characters
413 while (index < length) {
414 int c = _buffer.codeUnitAt(index);
415 if (!isWhitespace(c) || c == 0x0D || c == 0x0A) {
416 break;
417 }
418 index++;
419 }
420 // skip single \r
421 if (index < length && _buffer.codeUnitAt(index) == 0x0D) {
422 index++;
423 }
424 // skip single \n
425 if (index < length && _buffer.codeUnitAt(index) == 0x0A) {
426 index++;
427 }
428 // done
429 return index;
430 }
431
432 /**
433 * Skips spaces and tabs on the left from [index].
434 *
435 * If [index] is the start or a statement, then in the most cases it is a
436 * start on its line.
437 */
438 int getLineContentStart(int index) {
439 while (index > 0) {
440 int c = _buffer.codeUnitAt(index - 1);
441 if (!isSpace(c)) {
442 break;
443 }
444 index--;
445 }
446 return index;
447 }
448
449 /**
450 * Returns a start index of the next line after the line which contains the
451 * given index.
452 */
453 int getLineNext(int index) {
454 int length = _buffer.length;
455 // skip to the end of the line
456 while (index < length) {
457 int c = _buffer.codeUnitAt(index);
458 if (c == 0xD || c == 0xA) {
459 break;
460 }
461 index++;
462 }
463 // skip single \r
464 if (index < length && _buffer.codeUnitAt(index) == 0xD) {
465 index++;
466 }
467 // skip single \n
468 if (index < length && _buffer.codeUnitAt(index) == 0xA) {
469 index++;
470 }
471 // done
472 return index;
473 }
474
475 /**
476 * Returns the whitespace prefix of the line which contains given offset.
477 */
478 String getLinePrefix(int index) {
479 int lineStart = getLineThis(index);
480 int length = _buffer.length;
481 int lineNonWhitespace = lineStart;
482 while (lineNonWhitespace < length) {
483 int c = _buffer.codeUnitAt(lineNonWhitespace);
484 if (c == 0xD || c == 0xA) {
485 break;
486 }
487 if (!isWhitespace(c)) {
488 break;
489 }
490 lineNonWhitespace++;
491 }
492 return getText(lineStart, lineNonWhitespace - lineStart);
493 }
494
495 /**
496 * Returns the start index of the line which contains given index.
497 */
498 int getLineThis(int index) {
499 while (index > 0) {
500 int c = _buffer.codeUnitAt(index - 1);
501 if (c == 0xD || c == 0xA) {
502 break;
503 }
504 index--;
505 }
506 return index;
507 }
508
509 /**
510 * Returns a [SourceRange] that covers [range] and extends (if possible) to
511 * cover whole lines.
512 */
513 SourceRange getLinesRange(SourceRange range) {
514 // start
515 int startOffset = range.offset;
516 int startLineOffset = getLineContentStart(startOffset);
517 // end
518 int endOffset = range.end;
519 int afterEndLineOffset = getLineContentEnd(endOffset);
520 // range
521 return rangeStartEnd(startLineOffset, afterEndLineOffset);
522 }
523
524 /**
525 * Returns a [SourceRange] that covers all the given [Statement]s.
526 */
527 SourceRange getLinesRangeStatements(List<Statement> statements) {
528 SourceRange range = rangeNodes(statements);
529 return getLinesRange(range);
530 }
531
532 /**
533 * Returns the line prefix consisting of spaces and tabs on the left from the given
534 * [AstNode].
535 */
536 String getNodePrefix(AstNode node) {
537 int offset = node.offset;
538 // function literal is special, it uses offset of enclosing line
539 if (node is FunctionExpression) {
540 return getLinePrefix(offset);
541 }
542 // use just prefix directly before node
543 return getPrefix(offset);
544 }
545
546 /**
547 * Returns the text of the given [AstNode] in the unit.
548 */
549 String getNodeText(AstNode node) {
550 return getText(node.offset, node.length);
551 }
552
553 /**
554 * @return the source for the parameter with the given type and name.
555 */
556 String getParameterSource(DartType type, String name) {
557 // no type
558 if (type == null || type.isDynamic) {
559 return name;
560 }
561 // function type
562 if (type is FunctionType) {
563 FunctionType functionType = type;
564 StringBuffer sb = new StringBuffer();
565 // return type
566 DartType returnType = functionType.returnType;
567 if (returnType != null && !returnType.isDynamic) {
568 sb.write(getTypeSource(returnType));
569 sb.write(' ');
570 }
571 // parameter name
572 sb.write(name);
573 // parameters
574 sb.write('(');
575 List<ParameterElement> fParameters = functionType.parameters;
576 for (int i = 0; i < fParameters.length; i++) {
577 ParameterElement fParameter = fParameters[i];
578 if (i != 0) {
579 sb.write(", ");
580 }
581 sb.write(getParameterSource(fParameter.type, fParameter.name));
582 }
583 sb.write(')');
584 // done
585 return sb.toString();
586 }
587 // simple type
588 return "${getTypeSource(type)} ${name}";
589 }
590
591 /**
592 * Returns the line prefix consisting of spaces and tabs on the left from the
593 * given offset.
594 */
595 String getPrefix(int endIndex) {
596 int startIndex = getLineContentStart(endIndex);
597 return _buffer.substring(startIndex, endIndex);
598 }
599
600 /**
601 * Returns the text of the given range in the unit.
602 */
603 String getRangeText(SourceRange range) {
604 return getText(range.offset, range.length);
605 }
606
607 /**
608 * Returns the text of the given range in the unit.
609 */
610 String getText(int offset, int length) {
611 return _buffer.substring(offset, offset + length);
612 }
613
614 /**
615 * Returns the source to reference [type] in this [CompilationUnit].
616 */
617 String getTypeSource(DartType type) {
618 StringBuffer sb = new StringBuffer();
619 // just some Function, maybe find Function Type Alias later
620 if (type is FunctionType) {
621 return "Function";
622 }
623 // prepare element
624 Element element = type.element;
625 if (element == null) {
626 String source = type.toString();
627 source = source.replaceAll('<dynamic>', '');
628 source = source.replaceAll('<dynamic, dynamic>', '');
629 return source;
630 }
631 // append prefix
632 {
633 ImportElement imp = _getImportElement(element);
634 if (imp != null && imp.prefix != null) {
635 sb.write(imp.prefix.displayName);
636 sb.write(".");
637 }
638 }
639 // append simple name
640 String name = element.displayName;
641 sb.write(name);
642 // may be type arguments
643 if (type is InterfaceType) {
644 InterfaceType interfaceType = type;
645 List<DartType> arguments = interfaceType.typeArguments;
646 // check if has arguments
647 bool hasArguments = false;
648 for (DartType argument in arguments) {
649 if (!argument.isDynamic) {
650 hasArguments = true;
651 break;
652 }
653 }
654 // append type arguments
655 if (hasArguments) {
656 sb.write("<");
657 for (int i = 0; i < arguments.length; i++) {
658 DartType argument = arguments[i];
659 if (i != 0) {
660 sb.write(", ");
661 }
662 sb.write(getTypeSource(argument));
663 }
664 sb.write(">");
665 }
666 }
667 // done
668 return sb.toString();
669 }
670
671 /**
672 * Indents given source left or right.
673 */
674 String indentSourceLeftRight(String source, bool right) {
675 StringBuffer sb = new StringBuffer();
676 String indent = getIndent(1);
677 String eol = endOfLine;
678 List<String> lines = source.split(eol);
679 for (int i = 0; i < lines.length; i++) {
680 String line = lines[i];
681 // last line, stop if empty
682 if (i == lines.length - 1 && isEmpty(line)) {
683 break;
684 }
685 // update line
686 if (right) {
687 line = "${indent}${line}";
688 } else {
689 line = removeStart(line, indent);
690 }
691 // append line
692 sb.write(line);
693 sb.write(eol);
694 }
695 return sb.toString();
696 }
697
698 /**
699 * @return the source of the inverted condition for the given logical expressi on.
700 */
701 String invertCondition(Expression expression) =>
702 _invertCondition0(expression)._source;
703
704 /**
705 * Returns the source with indentation changed from [oldIndent] to
706 * [newIndent], keeping indentation of lines relative to each other.
707 */
708 String replaceSourceIndent(String source, String oldIndent,
709 String newIndent) {
710 // prepare STRING token ranges
711 List<SourceRange> lineRanges = [];
712 {
713 var token = unit.beginToken;
714 while (token != null && token.type != TokenType.EOF) {
715 if (token.type == TokenType.STRING) {
716 lineRanges.add(rangeToken(token));
717 }
718 token = token.next;
719 }
720 }
721 // re-indent lines
722 StringBuffer sb = new StringBuffer();
723 String eol = endOfLine;
724 List<String> lines = source.split(eol);
725 int lineOffset = 0;
726 for (int i = 0; i < lines.length; i++) {
727 String line = lines[i];
728 // last line, stop if empty
729 if (i == lines.length - 1 && isEmpty(line)) {
730 break;
731 }
732 // check if "offset" is in one of the String ranges
733 bool inString = false;
734 for (SourceRange lineRange in lineRanges) {
735 if (lineOffset > lineRange.offset && lineOffset < lineRange.end) {
736 inString = true;
737 }
738 if (lineOffset > lineRange.end) {
739 break;
740 }
741 }
742 lineOffset += line.length + eol.length;
743 // update line indent
744 if (!inString) {
745 line = "${newIndent}${removeStart(line, oldIndent)}";
746 }
747 // append line
748 sb.write(line);
749 sb.write(eol);
750 }
751 return sb.toString();
752 }
753
754 /**
755 * Returns the source of the given [SourceRange] with indentation changed
756 * from [oldIndent] to [newIndent], keeping indentation of lines relative
757 * to each other.
758 */
759 String replaceSourceRangeIndent(SourceRange range, String oldIndent,
760 String newIndent) {
761 String oldSource = getRangeText(range);
762 return replaceSourceIndent(oldSource, oldIndent, newIndent);
763 }
764
765 /**
766 * @return the [ImportElement] used to import given [Element] into [library].
767 * May be `null` if was not imported, i.e. declared in the same librar y.
768 */
769 ImportElement _getImportElement(Element element) {
770 for (ImportElement imp in _library.imports) {
771 Map<String, Element> definedNames = getImportNamespace(imp);
772 if (definedNames.containsValue(element)) {
773 return imp;
774 }
775 }
776 return null;
777 }
778
779 /**
780 * @return the [InvertedCondition] for the given logical expression.
781 */
782 _InvertedCondition _invertCondition0(Expression expression) {
783 if (expression is BooleanLiteral) {
784 BooleanLiteral literal = expression;
785 if (literal.value) {
786 return _InvertedCondition._simple("false");
787 } else {
788 return _InvertedCondition._simple("true");
789 }
790 }
791 if (expression is BinaryExpression) {
792 BinaryExpression binary = expression;
793 TokenType operator = binary.operator.type;
794 Expression le = binary.leftOperand;
795 Expression re = binary.rightOperand;
796 _InvertedCondition ls = _invertCondition0(le);
797 _InvertedCondition rs = _invertCondition0(re);
798 if (operator == TokenType.LT) {
799 return _InvertedCondition._binary2(ls, " >= ", rs);
800 }
801 if (operator == TokenType.GT) {
802 return _InvertedCondition._binary2(ls, " <= ", rs);
803 }
804 if (operator == TokenType.LT_EQ) {
805 return _InvertedCondition._binary2(ls, " > ", rs);
806 }
807 if (operator == TokenType.GT_EQ) {
808 return _InvertedCondition._binary2(ls, " < ", rs);
809 }
810 if (operator == TokenType.EQ_EQ) {
811 return _InvertedCondition._binary2(ls, " != ", rs);
812 }
813 if (operator == TokenType.BANG_EQ) {
814 return _InvertedCondition._binary2(ls, " == ", rs);
815 }
816 if (operator == TokenType.AMPERSAND_AMPERSAND) {
817 return _InvertedCondition._binary(
818 TokenType.BAR_BAR.precedence,
819 ls,
820 " || ",
821 rs);
822 }
823 if (operator == TokenType.BAR_BAR) {
824 return _InvertedCondition._binary(
825 TokenType.AMPERSAND_AMPERSAND.precedence,
826 ls,
827 " && ",
828 rs);
829 }
830 }
831 if (expression is IsExpression) {
832 IsExpression isExpression = expression;
833 String expressionSource = getNodeText(isExpression.expression);
834 String typeSource = getNodeText(isExpression.type);
835 if (isExpression.notOperator == null) {
836 return _InvertedCondition._simple(
837 "${expressionSource} is! ${typeSource}");
838 } else {
839 return _InvertedCondition._simple(
840 "${expressionSource} is ${typeSource}");
841 }
842 }
843 if (expression is PrefixExpression) {
844 PrefixExpression prefixExpression = expression;
845 TokenType operator = prefixExpression.operator.type;
846 if (operator == TokenType.BANG) {
847 Expression operand = prefixExpression.operand;
848 while (operand is ParenthesizedExpression) {
849 ParenthesizedExpression pe = operand as ParenthesizedExpression;
850 operand = pe.expression;
851 }
852 return _InvertedCondition._simple(getNodeText(operand));
853 }
854 }
855 if (expression is ParenthesizedExpression) {
856 ParenthesizedExpression pe = expression;
857 Expression innerExpresion = pe.expression;
858 while (innerExpresion is ParenthesizedExpression) {
859 innerExpresion = (innerExpresion as ParenthesizedExpression).expression;
860 }
861 return _invertCondition0(innerExpresion);
862 }
863 DartType type = expression.bestType;
864 if (type.displayName == "bool") {
865 return _InvertedCondition._simple("!${getNodeText(expression)}");
866 }
867 return _InvertedCondition._simple(getNodeText(expression));
868 }
869 }
870
871
872 /**
873 * Describes where to insert new directive or top-level declaration.
874 */
875 class CorrectionUtils_InsertDesc {
876 int offset = 0;
877 String prefix = "";
878 String suffix = "";
879 }
880
881
882 /**
883 * A container with a source and its precedence.
884 */
885 class _InvertedCondition {
886 final int _precedence;
887
888 final String _source;
889
890 _InvertedCondition(this._precedence, this._source);
891
892 static _InvertedCondition _binary(int precedence, _InvertedCondition left,
893 String operation, _InvertedCondition right) {
894 String src =
895 _parenthesizeIfRequired(left, precedence) +
896 operation +
897 _parenthesizeIfRequired(right, precedence);
898 return new _InvertedCondition(precedence, src);
899 }
900
901 static _InvertedCondition _binary2(_InvertedCondition left, String operation,
902 _InvertedCondition right) {
903 // TODO(scheglov) conside merging with "_binary()" after testing
904 return new _InvertedCondition(
905 1 << 20,
906 "${left._source}${operation}${right._source}");
907 }
908
909 /**
910 * Adds enclosing parenthesis if the precedence of the [_InvertedCondition] if less than the
911 * precedence of the expression we are going it to use in.
912 */
913 static String _parenthesizeIfRequired(_InvertedCondition expr,
914 int newOperatorPrecedence) {
915 if (expr._precedence < newOperatorPrecedence) {
916 return "(${expr._source})";
917 }
918 return expr._source;
919 }
920
921 static _InvertedCondition _simple(String source) =>
922 new _InvertedCondition(2147483647, source);
923 }
OLDNEW
« no previous file with comments | « pkg/analysis_services/lib/src/correction/strings.dart ('k') | pkg/analysis_services/lib/src/generated/change.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698