| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |