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 library services.src.correction.util; | 5 library services.src.correction.util; |
6 | 6 |
7 import 'dart:math'; | 7 import 'dart:math'; |
8 | 8 |
9 import 'package:analysis_server/plugin/protocol/protocol.dart' | 9 import 'package:analysis_server/plugin/protocol/protocol.dart' |
10 show SourceChange, SourceEdit; | 10 show SourceChange, SourceEdit; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 Object element = lists[0][position]; | 71 Object element = lists[0][position]; |
72 for (List list in lists) { | 72 for (List list in lists) { |
73 if (list[position] != element) { | 73 if (list[position] != element) { |
74 return false; | 74 return false; |
75 } | 75 } |
76 } | 76 } |
77 return true; | 77 return true; |
78 } | 78 } |
79 | 79 |
80 /** | 80 /** |
81 * Climbs up [PrefixedIdentifier] and [ProperyAccess] nodes that include [node]. | 81 * Climbs up [PrefixedIdentifier] and [PropertyAccess] nodes that include [node]
. |
82 */ | 82 */ |
83 Expression climbPropertyAccess(AstNode node) { | 83 Expression climbPropertyAccess(AstNode node) { |
84 while (true) { | 84 while (true) { |
85 AstNode parent = node.parent; | 85 AstNode parent = node.parent; |
86 if (parent is PrefixedIdentifier && parent.identifier == node) { | 86 if (parent is PrefixedIdentifier && parent.identifier == node) { |
87 node = parent; | 87 node = parent; |
88 continue; | 88 continue; |
89 } | 89 } |
90 if (parent is PropertyAccess && parent.propertyName == node) { | 90 if (parent is PropertyAccess && parent.propertyName == node) { |
91 node = parent; | 91 node = parent; |
(...skipping 1136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1228 * @return <code>true</code> if "selection" covers "node" and there are any no
n-whitespace tokens | 1228 * @return <code>true</code> if "selection" covers "node" and there are any no
n-whitespace tokens |
1229 * between "selection" and "node" start/end. | 1229 * between "selection" and "node" start/end. |
1230 */ | 1230 */ |
1231 bool selectionIncludesNonWhitespaceOutsideNode( | 1231 bool selectionIncludesNonWhitespaceOutsideNode( |
1232 SourceRange selection, AstNode node) { | 1232 SourceRange selection, AstNode node) { |
1233 return _selectionIncludesNonWhitespaceOutsideRange( | 1233 return _selectionIncludesNonWhitespaceOutsideRange( |
1234 selection, rangeNode(node)); | 1234 selection, rangeNode(node)); |
1235 } | 1235 } |
1236 | 1236 |
1237 /** | 1237 /** |
1238 * @return <code>true</code> if given range of [BinaryExpression] can be extra
cted. | |
1239 */ | |
1240 bool validateBinaryExpressionRange( | |
1241 BinaryExpression binaryExpression, SourceRange range) { | |
1242 // only parts of associative expression are safe to extract | |
1243 if (!binaryExpression.operator.type.isAssociativeOperator) { | |
1244 return false; | |
1245 } | |
1246 // prepare selected operands | |
1247 List<Expression> operands = _getOperandsInOrderFor(binaryExpression); | |
1248 List<Expression> subOperands = _getOperandsForSourceRange(operands, range); | |
1249 // if empty, then something wrong with selection | |
1250 if (subOperands.isEmpty) { | |
1251 return false; | |
1252 } | |
1253 // may be some punctuation included into selection - operators, braces, etc | |
1254 if (_selectionIncludesNonWhitespaceOutsideOperands(range, subOperands)) { | |
1255 return false; | |
1256 } | |
1257 // OK | |
1258 return true; | |
1259 } | |
1260 | |
1261 /** | |
1262 * @return the [ImportElement] used to import given [Element] into [library]. | 1238 * @return the [ImportElement] used to import given [Element] into [library]. |
1263 * May be `null` if was not imported, i.e. declared in the same librar
y. | 1239 * May be `null` if was not imported, i.e. declared in the same librar
y. |
1264 */ | 1240 */ |
1265 ImportElement _getImportElement(Element element) { | 1241 ImportElement _getImportElement(Element element) { |
1266 for (ImportElement imp in _library.imports) { | 1242 for (ImportElement imp in _library.imports) { |
1267 Map<String, Element> definedNames = getImportNamespace(imp); | 1243 Map<String, Element> definedNames = getImportNamespace(imp); |
1268 if (definedNames.containsValue(element)) { | 1244 if (definedNames.containsValue(element)) { |
1269 return imp; | 1245 return imp; |
1270 } | 1246 } |
1271 } | 1247 } |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1337 Expression operand = prefixExpression.operand; | 1313 Expression operand = prefixExpression.operand; |
1338 while (operand is ParenthesizedExpression) { | 1314 while (operand is ParenthesizedExpression) { |
1339 ParenthesizedExpression pe = operand as ParenthesizedExpression; | 1315 ParenthesizedExpression pe = operand as ParenthesizedExpression; |
1340 operand = pe.expression; | 1316 operand = pe.expression; |
1341 } | 1317 } |
1342 return _InvertedCondition._simple(getNodeText(operand)); | 1318 return _InvertedCondition._simple(getNodeText(operand)); |
1343 } | 1319 } |
1344 } | 1320 } |
1345 if (expression is ParenthesizedExpression) { | 1321 if (expression is ParenthesizedExpression) { |
1346 ParenthesizedExpression pe = expression; | 1322 ParenthesizedExpression pe = expression; |
1347 Expression innerExpresion = pe.expression; | 1323 Expression innerExpression = pe.expression; |
1348 while (innerExpresion is ParenthesizedExpression) { | 1324 while (innerExpression is ParenthesizedExpression) { |
1349 innerExpresion = (innerExpresion as ParenthesizedExpression).expression; | 1325 innerExpression = |
| 1326 (innerExpression as ParenthesizedExpression).expression; |
1350 } | 1327 } |
1351 return _invertCondition0(innerExpresion); | 1328 return _invertCondition0(innerExpression); |
1352 } | 1329 } |
1353 DartType type = expression.bestType; | 1330 DartType type = expression.bestType; |
1354 if (type.displayName == "bool") { | 1331 if (type.displayName == "bool") { |
1355 return _InvertedCondition._simple("!${getNodeText(expression)}"); | 1332 return _InvertedCondition._simple("!${getNodeText(expression)}"); |
1356 } | 1333 } |
1357 return _InvertedCondition._simple(getNodeText(expression)); | 1334 return _InvertedCondition._simple(getNodeText(expression)); |
1358 } | 1335 } |
1359 | 1336 |
1360 /** | 1337 /** |
1361 * Checks if [type] is visible at [targetOffset]. | 1338 * Checks if [type] is visible at [targetOffset]. |
1362 */ | 1339 */ |
1363 bool _isTypeVisible(DartType type) { | 1340 bool _isTypeVisible(DartType type) { |
1364 if (type is TypeParameterType) { | 1341 if (type is TypeParameterType) { |
1365 TypeParameterElement parameterElement = type.element; | 1342 TypeParameterElement parameterElement = type.element; |
1366 Element parameterClassElement = parameterElement.enclosingElement; | 1343 Element parameterClassElement = parameterElement.enclosingElement; |
1367 return identical(parameterClassElement, targetClassElement); | 1344 return identical(parameterClassElement, targetClassElement); |
1368 } | 1345 } |
1369 return true; | 1346 return true; |
1370 } | 1347 } |
1371 | 1348 |
1372 bool _selectionIncludesNonWhitespaceOutsideOperands( | |
1373 SourceRange selection, List<Expression> operands) { | |
1374 return _selectionIncludesNonWhitespaceOutsideRange( | |
1375 selection, rangeNodes(operands)); | |
1376 } | |
1377 | |
1378 /** | 1349 /** |
1379 * @return <code>true</code> if "selection" covers "range" and there are any n
on-whitespace tokens | 1350 * @return <code>true</code> if "selection" covers "range" and there are any n
on-whitespace tokens |
1380 * between "selection" and "range" start/end. | 1351 * between "selection" and "range" start/end. |
1381 */ | 1352 */ |
1382 bool _selectionIncludesNonWhitespaceOutsideRange( | 1353 bool _selectionIncludesNonWhitespaceOutsideRange( |
1383 SourceRange selection, SourceRange range) { | 1354 SourceRange selection, SourceRange range) { |
1384 // selection should cover range | 1355 // selection should cover range |
1385 if (!selection.covers(range)) { | 1356 if (!selection.covers(range)) { |
1386 return false; | 1357 return false; |
1387 } | 1358 } |
1388 // non-whitespace between selection start and range start | 1359 // non-whitespace between selection start and range start |
1389 if (!isJustWhitespaceOrComment(rangeStartStart(selection, range))) { | 1360 if (!isJustWhitespaceOrComment(rangeStartStart(selection, range))) { |
1390 return true; | 1361 return true; |
1391 } | 1362 } |
1392 // non-whitespace after range | 1363 // non-whitespace after range |
1393 if (!isJustWhitespaceOrComment(rangeEndEnd(range, selection))) { | 1364 if (!isJustWhitespaceOrComment(rangeEndEnd(range, selection))) { |
1394 return true; | 1365 return true; |
1395 } | 1366 } |
1396 // only whitespace in selection around range | 1367 // only whitespace in selection around range |
1397 return false; | 1368 return false; |
1398 } | 1369 } |
1399 | |
1400 /** | |
1401 * @return [Expression]s from <code>operands</code> which are completely cover
ed by given | |
1402 * [SourceRange]. Range should start and end between given [Expression
]s. | |
1403 */ | |
1404 static List<Expression> _getOperandsForSourceRange( | |
1405 List<Expression> operands, SourceRange range) { | |
1406 assert(!operands.isEmpty); | |
1407 List<Expression> subOperands = []; | |
1408 // track range enter/exit | |
1409 bool entered = false; | |
1410 bool exited = false; | |
1411 // may be range starts before or on first operand | |
1412 if (range.offset <= operands[0].offset) { | |
1413 entered = true; | |
1414 } | |
1415 // iterate over gaps between operands | |
1416 for (int i = 0; i < operands.length - 1; i++) { | |
1417 Expression operand = operands[i]; | |
1418 Expression nextOperand = operands[i + 1]; | |
1419 SourceRange inclusiveGap = | |
1420 rangeEndStart(operand, nextOperand).getMoveEnd(1); | |
1421 // add operand, if already entered range | |
1422 if (entered) { | |
1423 subOperands.add(operand); | |
1424 // may be last operand in range | |
1425 if (range.endsIn(inclusiveGap)) { | |
1426 exited = true; | |
1427 } | |
1428 } else { | |
1429 // may be first operand in range | |
1430 if (range.startsIn(inclusiveGap)) { | |
1431 entered = true; | |
1432 } | |
1433 } | |
1434 } | |
1435 // check if last operand is in range | |
1436 Expression lastGroupMember = operands[operands.length - 1]; | |
1437 if (range.end == lastGroupMember.end) { | |
1438 subOperands.add(lastGroupMember); | |
1439 exited = true; | |
1440 } | |
1441 // we expect that range covers only given operands | |
1442 if (!exited) { | |
1443 return []; | |
1444 } | |
1445 // done | |
1446 return subOperands; | |
1447 } | |
1448 | |
1449 /** | |
1450 * @return all operands of the given [BinaryExpression] and its children with
the same | |
1451 * operator. | |
1452 */ | |
1453 static List<Expression> _getOperandsInOrderFor(BinaryExpression groupRoot) { | |
1454 List<Expression> operands = []; | |
1455 TokenType groupOperatorType = groupRoot.operator.type; | |
1456 groupRoot.accept(new _OrderedOperandsVisitor(groupOperatorType, operands)); | |
1457 return operands; | |
1458 } | |
1459 } | 1370 } |
1460 | 1371 |
1461 /** | 1372 /** |
1462 * Describes where to insert new directive or top-level declaration. | 1373 * Describes where to insert new directive or top-level declaration. |
1463 */ | 1374 */ |
1464 class CorrectionUtils_InsertDesc { | 1375 class CorrectionUtils_InsertDesc { |
1465 int offset = 0; | 1376 int offset = 0; |
1466 String prefix = ""; | 1377 String prefix = ""; |
1467 String suffix = ""; | 1378 String suffix = ""; |
1468 } | 1379 } |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1540 static _InvertedCondition _binary(int precedence, _InvertedCondition left, | 1451 static _InvertedCondition _binary(int precedence, _InvertedCondition left, |
1541 String operation, _InvertedCondition right) { | 1452 String operation, _InvertedCondition right) { |
1542 String src = _parenthesizeIfRequired(left, precedence) + | 1453 String src = _parenthesizeIfRequired(left, precedence) + |
1543 operation + | 1454 operation + |
1544 _parenthesizeIfRequired(right, precedence); | 1455 _parenthesizeIfRequired(right, precedence); |
1545 return new _InvertedCondition(precedence, src); | 1456 return new _InvertedCondition(precedence, src); |
1546 } | 1457 } |
1547 | 1458 |
1548 static _InvertedCondition _binary2( | 1459 static _InvertedCondition _binary2( |
1549 _InvertedCondition left, String operation, _InvertedCondition right) { | 1460 _InvertedCondition left, String operation, _InvertedCondition right) { |
1550 // TODO(scheglov) conside merging with "_binary()" after testing | 1461 // TODO(scheglov) consider merging with "_binary()" after testing |
1551 return new _InvertedCondition( | 1462 return new _InvertedCondition( |
1552 1 << 20, "${left._source}${operation}${right._source}"); | 1463 1 << 20, "${left._source}${operation}${right._source}"); |
1553 } | 1464 } |
1554 | 1465 |
1555 /** | 1466 /** |
1556 * Adds enclosing parenthesis if the precedence of the [_InvertedCondition] if
less than the | 1467 * Adds enclosing parenthesis if the precedence of the [_InvertedCondition] if
less than the |
1557 * precedence of the expression we are going it to use in. | 1468 * precedence of the expression we are going it to use in. |
1558 */ | 1469 */ |
1559 static String _parenthesizeIfRequired( | 1470 static String _parenthesizeIfRequired( |
1560 _InvertedCondition expr, int newOperatorPrecedence) { | 1471 _InvertedCondition expr, int newOperatorPrecedence) { |
1561 if (expr._precedence < newOperatorPrecedence) { | 1472 if (expr._precedence < newOperatorPrecedence) { |
1562 return "(${expr._source})"; | 1473 return "(${expr._source})"; |
1563 } | 1474 } |
1564 return expr._source; | 1475 return expr._source; |
1565 } | 1476 } |
1566 | 1477 |
1567 static _InvertedCondition _simple(String source) => | 1478 static _InvertedCondition _simple(String source) => |
1568 new _InvertedCondition(2147483647, source); | 1479 new _InvertedCondition(2147483647, source); |
1569 } | 1480 } |
1570 | |
1571 class _OrderedOperandsVisitor extends GeneralizingAstVisitor { | |
1572 final TokenType groupOperatorType; | |
1573 final List<Expression> operands; | |
1574 | |
1575 _OrderedOperandsVisitor(this.groupOperatorType, this.operands); | |
1576 | |
1577 @override | |
1578 Object visitExpression(Expression node) { | |
1579 if (node is BinaryExpression && node.operator.type == groupOperatorType) { | |
1580 return super.visitNode(node); | |
1581 } | |
1582 operands.add(node); | |
1583 return null; | |
1584 } | |
1585 } | |
OLD | NEW |