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

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

Issue 1431673003: Compute covering offsets/lengths. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 1 month 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
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 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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698