| Index: pkg/analysis_services/lib/src/correction/assist.dart
|
| diff --git a/pkg/analysis_services/lib/src/correction/assist.dart b/pkg/analysis_services/lib/src/correction/assist.dart
|
| deleted file mode 100644
|
| index 9415683c1c75cdfd3dcbce2aa323224c860f2d35..0000000000000000000000000000000000000000
|
| --- a/pkg/analysis_services/lib/src/correction/assist.dart
|
| +++ /dev/null
|
| @@ -1,1589 +0,0 @@
|
| -// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -library services.src.correction.assist;
|
| -
|
| -import 'dart:collection';
|
| -
|
| -import 'package:analysis_services/correction/assist.dart';
|
| -import 'package:analysis_services/correction/change.dart';
|
| -import 'package:analysis_services/search/hierarchy.dart';
|
| -import 'package:analysis_services/search/search_engine.dart';
|
| -import 'package:analysis_services/src/correction/name_suggestion.dart';
|
| -import 'package:analysis_services/src/correction/source_buffer.dart';
|
| -import 'package:analysis_services/src/correction/source_range.dart';
|
| -import 'package:analysis_services/src/correction/statement_analyzer.dart';
|
| -import 'package:analysis_services/src/correction/util.dart';
|
| -import 'package:analyzer/src/generated/ast.dart';
|
| -import 'package:analyzer/src/generated/element.dart';
|
| -import 'package:analyzer/src/generated/java_core.dart';
|
| -import 'package:analyzer/src/generated/scanner.dart';
|
| -import 'package:analyzer/src/generated/source.dart';
|
| -import 'package:path/path.dart';
|
| -
|
| -
|
| -
|
| -typedef _SimpleIdentifierVisitor(SimpleIdentifier node);
|
| -
|
| -
|
| -/**
|
| - * The computer for Dart assists.
|
| - */
|
| -class AssistProcessor {
|
| - final SearchEngine searchEngine;
|
| - final Source source;
|
| - final String file;
|
| - final CompilationUnit unit;
|
| - final int selectionOffset;
|
| - final int selectionLength;
|
| - CompilationUnitElement unitElement;
|
| - LibraryElement unitLibraryElement;
|
| - String unitLibraryFile;
|
| - String unitLibraryFolder;
|
| -
|
| - final List<Edit> edits = <Edit>[];
|
| - final Map<String, LinkedEditGroup> linkedPositionGroups = <String,
|
| - LinkedEditGroup>{};
|
| - Position exitPosition = null;
|
| - final List<Assist> assists = <Assist>[];
|
| -
|
| - int selectionEnd;
|
| - CorrectionUtils utils;
|
| - AstNode node;
|
| -
|
| - AssistProcessor(this.searchEngine, this.source, this.file, this.unit,
|
| - this.selectionOffset, this.selectionLength) {
|
| - unitElement = unit.element;
|
| - unitLibraryElement = unitElement.library;
|
| - unitLibraryFile = unitLibraryElement.source.fullName;
|
| - unitLibraryFolder = dirname(unitLibraryFile);
|
| - selectionEnd = selectionOffset + selectionLength;
|
| - }
|
| -
|
| - /**
|
| - * Returns the EOL to use for this [CompilationUnit].
|
| - */
|
| - String get eol => utils.endOfLine;
|
| -
|
| - List<Assist> compute() {
|
| - utils = new CorrectionUtils(unit);
|
| - node = new NodeLocator.con2(
|
| - selectionOffset,
|
| - selectionEnd).searchWithin(unit);
|
| - // try to add proposals
|
| - _addProposal_addTypeAnnotation();
|
| - _addProposal_assignToLocalVariable();
|
| - _addProposal_convertToBlockFunctionBody();
|
| - _addProposal_convertToExpressionFunctionBody();
|
| - _addProposal_convertToIsNot_onIs();
|
| - _addProposal_convertToIsNot_onNot();
|
| - _addProposal_convertToIsNotEmpty();
|
| - _addProposal_exchangeOperands();
|
| - _addProposal_importAddShow();
|
| - _addProposal_invertIf();
|
| - _addProposal_joinIfStatementInner();
|
| - _addProposal_joinIfStatementOuter();
|
| - _addProposal_joinVariableDeclaration_onAssignment();
|
| - _addProposal_joinVariableDeclaration_onDeclaration();
|
| - _addProposal_removeTypeAnnotation();
|
| - _addProposal_replaceConditionalWithIfElse();
|
| - _addProposal_replaceIfElseWithConditional();
|
| - _addProposal_splitAndCondition();
|
| - _addProposal_splitVariableDeclaration();
|
| - _addProposal_surroundWith();
|
| - // done
|
| - return assists;
|
| - }
|
| -
|
| - FunctionBody getEnclosingFunctionBody() {
|
| - {
|
| - FunctionExpression function =
|
| - node.getAncestor((node) => node is FunctionExpression);
|
| - if (function != null) {
|
| - return function.body;
|
| - }
|
| - }
|
| - {
|
| - FunctionDeclaration function =
|
| - node.getAncestor((node) => node is FunctionDeclaration);
|
| - if (function != null) {
|
| - return function.functionExpression.body;
|
| - }
|
| - }
|
| - {
|
| - MethodDeclaration method =
|
| - node.getAncestor((node) => node is MethodDeclaration);
|
| - if (method != null) {
|
| - return method.body;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - void _addAssist(AssistKind kind, List args, {String assistFile}) {
|
| - if (assistFile == null) {
|
| - assistFile = file;
|
| - }
|
| - FileEdit fileEdit = new FileEdit(file);
|
| - fileEdit.addAll(edits);
|
| - // prepare Change
|
| - String message = formatList(kind.message, args);
|
| - Change change = new Change(message);
|
| - change.addFileEdit(fileEdit);
|
| - linkedPositionGroups.values.forEach(
|
| - (group) => change.addLinkedEditGroup(group));
|
| - change.selection = exitPosition;
|
| - // add Assist
|
| - Assist assist = new Assist(kind, change);
|
| - assists.add(assist);
|
| - // clear
|
| - edits.clear();
|
| - linkedPositionGroups.clear();
|
| - exitPosition = null;
|
| - }
|
| -
|
| - /**
|
| - * Adds a new [Edit] to [edits].
|
| - */
|
| - void _addInsertEdit(int offset, String text) {
|
| - Edit edit = new Edit(offset, 0, text);
|
| - edits.add(edit);
|
| - }
|
| -
|
| - void _addProposal_addTypeAnnotation() {
|
| - // prepare VariableDeclarationList
|
| - VariableDeclarationList declarationList =
|
| - node.getAncestor((node) => node is VariableDeclarationList);
|
| - if (declarationList == null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // may be has type annotation already
|
| - if (declarationList.type != null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare single VariableDeclaration
|
| - List<VariableDeclaration> variables = declarationList.variables;
|
| - if (variables.length != 1) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - VariableDeclaration variable = variables[0];
|
| - // we need an initializer to get the type from
|
| - Expression initializer = variable.initializer;
|
| - if (initializer == null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - DartType type = initializer.bestType;
|
| - // prepare type source
|
| - String typeSource;
|
| - if (type is InterfaceType || type is FunctionType) {
|
| - typeSource = utils.getTypeSource(type);
|
| - } else {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // add edit
|
| - Token keyword = declarationList.keyword;
|
| - if (keyword is KeywordToken && keyword.keyword == Keyword.VAR) {
|
| - SourceRange range = rangeToken(keyword);
|
| - _addReplaceEdit(range, typeSource);
|
| - } else {
|
| - _addInsertEdit(variable.offset, '$typeSource ');
|
| - }
|
| - // add proposal
|
| - _addAssist(AssistKind.ADD_TYPE_ANNOTATION, []);
|
| - }
|
| -
|
| - void _addProposal_assignToLocalVariable() {
|
| - // prepare enclosing ExpressionStatement
|
| - Statement statement = node.getAncestor((node) => node is Statement);
|
| - if (statement is! ExpressionStatement) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - ExpressionStatement expressionStatement = statement as ExpressionStatement;
|
| - // prepare expression
|
| - Expression expression = expressionStatement.expression;
|
| - int offset = expression.offset;
|
| - // ignore if already assignment
|
| - if (expression is AssignmentExpression) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // ignore "throw"
|
| - if (expression is ThrowExpression) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare expression type
|
| - DartType type = expression.bestType;
|
| - if (type.isVoid) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare source
|
| - SourceBuilder builder = new SourceBuilder(file, offset);
|
| - builder.append("var ");
|
| - // prepare excluded names
|
| - Set<String> excluded = new Set<String>();
|
| - {
|
| - ScopedNameFinder scopedNameFinder = new ScopedNameFinder(offset);
|
| - expression.accept(scopedNameFinder);
|
| - excluded.addAll(scopedNameFinder.locals.keys.toSet());
|
| - }
|
| - // name(s)
|
| - {
|
| - List<String> suggestions =
|
| - getVariableNameSuggestionsForExpression(type, expression, excluded);
|
| - builder.startPosition("NAME");
|
| - for (int i = 0; i < suggestions.length; i++) {
|
| - String name = suggestions[i];
|
| - if (i == 0) {
|
| - builder.append(name);
|
| - }
|
| - builder.addSuggestion(LinkedEditSuggestionKind.VARIABLE, name);
|
| - }
|
| - builder.endPosition();
|
| - }
|
| - builder.append(" = ");
|
| - // add proposal
|
| - _insertBuilder(builder);
|
| - _addAssist(AssistKind.ASSIGN_TO_LOCAL_VARIABLE, []);
|
| - }
|
| -
|
| - void _addProposal_convertToBlockFunctionBody() {
|
| - FunctionBody body = getEnclosingFunctionBody();
|
| - // prepare expression body
|
| - if (body is! ExpressionFunctionBody) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - Expression returnValue = (body as ExpressionFunctionBody).expression;
|
| - // prepare prefix
|
| - String prefix = utils.getNodePrefix(body.parent);
|
| - // add change
|
| - String indent = utils.getIndent(1);
|
| - String returnSource = 'return ' + _getNodeText(returnValue);
|
| - String newBodySource = "{$eol$prefix${indent}$returnSource;$eol$prefix}";
|
| - _addReplaceEdit(rangeNode(body), newBodySource);
|
| - // add proposal
|
| - _addAssist(AssistKind.CONVERT_INTO_BLOCK_BODY, []);
|
| - }
|
| -
|
| - void _addProposal_convertToExpressionFunctionBody() {
|
| - // prepare current body
|
| - FunctionBody body = getEnclosingFunctionBody();
|
| - if (body is! BlockFunctionBody) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare return statement
|
| - List<Statement> statements = (body as BlockFunctionBody).block.statements;
|
| - if (statements.length != 1) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - if (statements[0] is! ReturnStatement) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - ReturnStatement returnStatement = statements[0] as ReturnStatement;
|
| - // prepare returned expression
|
| - Expression returnExpression = returnStatement.expression;
|
| - if (returnExpression == null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // add change
|
| - String newBodySource = "=> ${_getNodeText(returnExpression)}";
|
| - if (body.parent is! FunctionExpression ||
|
| - body.parent.parent is FunctionDeclaration) {
|
| - newBodySource += ";";
|
| - }
|
| - _addReplaceEdit(rangeNode(body), newBodySource);
|
| - // add proposal
|
| - _addAssist(AssistKind.CONVERT_INTO_EXPRESSION_BODY, []);
|
| - }
|
| -
|
| - /**
|
| - * Converts "!isEmpty" -> "isNotEmpty" if possible.
|
| - */
|
| - void _addProposal_convertToIsNotEmpty() {
|
| - // prepare "expr.isEmpty"
|
| - AstNode isEmptyAccess = null;
|
| - SimpleIdentifier isEmptyIdentifier = null;
|
| - if (node is SimpleIdentifier) {
|
| - SimpleIdentifier identifier = node as SimpleIdentifier;
|
| - AstNode parent = identifier.parent;
|
| - // normal case (but rare)
|
| - if (parent is PropertyAccess) {
|
| - isEmptyIdentifier = parent.propertyName;
|
| - isEmptyAccess = parent;
|
| - }
|
| - // usual case
|
| - if (parent is PrefixedIdentifier) {
|
| - isEmptyIdentifier = parent.identifier;
|
| - isEmptyAccess = parent;
|
| - }
|
| - }
|
| - if (isEmptyIdentifier == null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // should be "isEmpty"
|
| - Element propertyElement = isEmptyIdentifier.bestElement;
|
| - if (propertyElement == null || "isEmpty" != propertyElement.name) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // should have "isNotEmpty"
|
| - Element propertyTarget = propertyElement.enclosingElement;
|
| - if (propertyTarget == null ||
|
| - getChildren(propertyTarget, "isNotEmpty").isEmpty) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // should be in PrefixExpression
|
| - if (isEmptyAccess.parent is! PrefixExpression) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - PrefixExpression prefixExpression =
|
| - isEmptyAccess.parent as PrefixExpression;
|
| - // should be !
|
| - if (prefixExpression.operator.type != TokenType.BANG) {
|
| - return;
|
| - }
|
| - // do replace
|
| - _addRemoveEdit(rangeStartStart(prefixExpression, prefixExpression.operand));
|
| - _addReplaceEdit(rangeNode(isEmptyIdentifier), "isNotEmpty");
|
| - // add proposal
|
| - _addAssist(AssistKind.CONVERT_INTO_IS_NOT_EMPTY, []);
|
| - }
|
| -
|
| - void _addProposal_convertToIsNot_onIs() {
|
| - // may be child of "is"
|
| - AstNode node = this.node;
|
| - while (node != null && node is! IsExpression) {
|
| - node = node.parent;
|
| - }
|
| - // prepare "is"
|
| - if (node is! IsExpression) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - IsExpression isExpression = node as IsExpression;
|
| - if (isExpression.notOperator != null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare enclosing ()
|
| - AstNode parent = isExpression.parent;
|
| - if (parent is! ParenthesizedExpression) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - ParenthesizedExpression parExpression = parent as ParenthesizedExpression;
|
| - // prepare enclosing !()
|
| - AstNode parent2 = parent.parent;
|
| - if (parent2 is! PrefixExpression) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - PrefixExpression prefExpression = parent2 as PrefixExpression;
|
| - if (prefExpression.operator.type != TokenType.BANG) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // strip !()
|
| - if (getExpressionParentPrecedence(prefExpression) >=
|
| - TokenType.IS.precedence) {
|
| - _addRemoveEdit(rangeToken(prefExpression.operator));
|
| - } else {
|
| - _addRemoveEdit(
|
| - rangeStartEnd(prefExpression, parExpression.leftParenthesis));
|
| - _addRemoveEdit(
|
| - rangeStartEnd(parExpression.rightParenthesis, prefExpression));
|
| - }
|
| - _addInsertEdit(isExpression.isOperator.end, "!");
|
| - // add proposal
|
| - _addAssist(AssistKind.CONVERT_INTO_IS_NOT, []);
|
| - }
|
| -
|
| - void _addProposal_convertToIsNot_onNot() {
|
| - // may be () in prefix expression
|
| - if (node is ParenthesizedExpression && node.parent is PrefixExpression) {
|
| - node = node.parent;
|
| - }
|
| - // prepare !()
|
| - if (node is! PrefixExpression) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - PrefixExpression prefExpression = node as PrefixExpression;
|
| - // should be ! operator
|
| - if (prefExpression.operator.type != TokenType.BANG) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare !()
|
| - Expression operand = prefExpression.operand;
|
| - if (operand is! ParenthesizedExpression) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - ParenthesizedExpression parExpression = operand as ParenthesizedExpression;
|
| - operand = parExpression.expression;
|
| - // prepare "is"
|
| - if (operand is! IsExpression) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - IsExpression isExpression = operand as IsExpression;
|
| - if (isExpression.notOperator != null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // strip !()
|
| - if (getExpressionParentPrecedence(prefExpression) >=
|
| - TokenType.IS.precedence) {
|
| - _addRemoveEdit(rangeToken(prefExpression.operator));
|
| - } else {
|
| - _addRemoveEdit(
|
| - rangeStartEnd(prefExpression, parExpression.leftParenthesis));
|
| - _addRemoveEdit(
|
| - rangeStartEnd(parExpression.rightParenthesis, prefExpression));
|
| - }
|
| - _addInsertEdit(isExpression.isOperator.end, "!");
|
| - // add proposal
|
| - _addAssist(AssistKind.CONVERT_INTO_IS_NOT, []);
|
| - }
|
| -
|
| - void _addProposal_exchangeOperands() {
|
| - // check that user invokes quick assist on binary expression
|
| - if (node is! BinaryExpression) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - BinaryExpression binaryExpression = node as BinaryExpression;
|
| - // prepare operator position
|
| - if (!_isOperatorSelected(
|
| - binaryExpression,
|
| - selectionOffset,
|
| - selectionLength)) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // add edits
|
| - {
|
| - Expression leftOperand = binaryExpression.leftOperand;
|
| - Expression rightOperand = binaryExpression.rightOperand;
|
| - // find "wide" enclosing binary expression with same operator
|
| - while (binaryExpression.parent is BinaryExpression) {
|
| - BinaryExpression newBinaryExpression =
|
| - binaryExpression.parent as BinaryExpression;
|
| - if (newBinaryExpression.operator.type !=
|
| - binaryExpression.operator.type) {
|
| - _coverageMarker();
|
| - break;
|
| - }
|
| - binaryExpression = newBinaryExpression;
|
| - }
|
| - // exchange parts of "wide" expression parts
|
| - SourceRange leftRange = rangeStartEnd(binaryExpression, leftOperand);
|
| - SourceRange rightRange = rangeStartEnd(rightOperand, binaryExpression);
|
| - _addReplaceEdit(leftRange, _getRangeText(rightRange));
|
| - _addReplaceEdit(rightRange, _getRangeText(leftRange));
|
| - }
|
| - // add proposal
|
| - _addAssist(AssistKind.EXCHANGE_OPERANDS, []);
|
| - }
|
| -
|
| - void _addProposal_importAddShow() {
|
| - // prepare ImportDirective
|
| - ImportDirective importDirective =
|
| - node.getAncestor((node) => node is ImportDirective);
|
| - if (importDirective == null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // there should be no existing combinators
|
| - if (importDirective.combinators.isNotEmpty) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare whole import namespace
|
| - ImportElement importElement = importDirective.element;
|
| - Map<String, Element> namespace = getImportNamespace(importElement);
|
| - // prepare names of referenced elements (from this import)
|
| - SplayTreeSet<String> referencedNames = new SplayTreeSet<String>();
|
| - _SimpleIdentifierRecursiveAstVisitor visitor =
|
| - new _SimpleIdentifierRecursiveAstVisitor((SimpleIdentifier node) {
|
| - Element element = node.staticElement;
|
| - if (namespace[node.name] == element) {
|
| - referencedNames.add(element.displayName);
|
| - }
|
| - });
|
| - unit.accept(visitor);
|
| - // ignore if unused
|
| - if (referencedNames.isEmpty) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare change
|
| - String showCombinator = " show ${StringUtils.join(referencedNames, ", ")}";
|
| - _addInsertEdit(importDirective.end - 1, showCombinator);
|
| - // add proposal
|
| - _addAssist(AssistKind.IMPORT_ADD_SHOW, []);
|
| - }
|
| -
|
| - void _addProposal_invertIf() {
|
| - if (node is! IfStatement) {
|
| - return;
|
| - }
|
| - IfStatement ifStatement = node as IfStatement;
|
| - Expression condition = ifStatement.condition;
|
| - // should have both "then" and "else"
|
| - Statement thenStatement = ifStatement.thenStatement;
|
| - Statement elseStatement = ifStatement.elseStatement;
|
| - if (thenStatement == null || elseStatement == null) {
|
| - return;
|
| - }
|
| - // prepare source
|
| - String invertedCondition = utils.invertCondition(condition);
|
| - String thenSource = _getNodeText(thenStatement);
|
| - String elseSource = _getNodeText(elseStatement);
|
| - // do replacements
|
| - _addReplaceEdit(rangeNode(condition), invertedCondition);
|
| - _addReplaceEdit(rangeNode(thenStatement), elseSource);
|
| - _addReplaceEdit(rangeNode(elseStatement), thenSource);
|
| - // add proposal
|
| - _addAssist(AssistKind.INVERT_IF_STATEMENT, []);
|
| - }
|
| -
|
| - void _addProposal_joinIfStatementInner() {
|
| - // climb up condition to the (supposedly) "if" statement
|
| - AstNode node = this.node;
|
| - while (node is Expression) {
|
| - node = node.parent;
|
| - }
|
| - // prepare target "if" statement
|
| - if (node is! IfStatement) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - IfStatement targetIfStatement = node as IfStatement;
|
| - if (targetIfStatement.elseStatement != null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare inner "if" statement
|
| - Statement targetThenStatement = targetIfStatement.thenStatement;
|
| - Statement innerStatement = getSingleStatement(targetThenStatement);
|
| - if (innerStatement is! IfStatement) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - IfStatement innerIfStatement = innerStatement as IfStatement;
|
| - if (innerIfStatement.elseStatement != null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare environment
|
| - String prefix = utils.getNodePrefix(targetIfStatement);
|
| - // merge conditions
|
| - String condition;
|
| - {
|
| - Expression targetCondition = targetIfStatement.condition;
|
| - Expression innerCondition = innerIfStatement.condition;
|
| - String targetConditionSource = _getNodeText(targetCondition);
|
| - String innerConditionSource = _getNodeText(innerCondition);
|
| - if (_shouldWrapParenthesisBeforeAnd(targetCondition)) {
|
| - targetConditionSource = "(${targetConditionSource})";
|
| - }
|
| - if (_shouldWrapParenthesisBeforeAnd(innerCondition)) {
|
| - innerConditionSource = "(${innerConditionSource})";
|
| - }
|
| - condition = "${targetConditionSource} && ${innerConditionSource}";
|
| - }
|
| - // replace target "if" statement
|
| - {
|
| - Statement innerThenStatement = innerIfStatement.thenStatement;
|
| - List<Statement> innerThenStatements = getStatements(innerThenStatement);
|
| - SourceRange lineRanges =
|
| - utils.getLinesRangeStatements(innerThenStatements);
|
| - String oldSource = utils.getRangeText(lineRanges);
|
| - String newSource = utils.indentSourceLeftRight(oldSource, false);
|
| - _addReplaceEdit(
|
| - rangeNode(targetIfStatement),
|
| - "if ($condition) {${eol}${newSource}${prefix}}");
|
| - }
|
| - // done
|
| - _addAssist(AssistKind.JOIN_IF_WITH_INNER, []);
|
| - }
|
| -
|
| - void _addProposal_joinIfStatementOuter() {
|
| - // climb up condition to the (supposedly) "if" statement
|
| - AstNode node = this.node;
|
| - while (node is Expression) {
|
| - node = node.parent;
|
| - }
|
| - // prepare target "if" statement
|
| - if (node is! IfStatement) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - IfStatement targetIfStatement = node as IfStatement;
|
| - if (targetIfStatement.elseStatement != null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare outer "if" statement
|
| - AstNode parent = targetIfStatement.parent;
|
| - if (parent is Block) {
|
| - parent = parent.parent;
|
| - }
|
| - if (parent is! IfStatement) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - IfStatement outerIfStatement = parent as IfStatement;
|
| - if (outerIfStatement.elseStatement != null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare environment
|
| - String prefix = utils.getNodePrefix(outerIfStatement);
|
| - // merge conditions
|
| - String condition;
|
| - {
|
| - Expression targetCondition = targetIfStatement.condition;
|
| - Expression outerCondition = outerIfStatement.condition;
|
| - String targetConditionSource = _getNodeText(targetCondition);
|
| - String outerConditionSource = _getNodeText(outerCondition);
|
| - if (_shouldWrapParenthesisBeforeAnd(targetCondition)) {
|
| - targetConditionSource = "(${targetConditionSource})";
|
| - }
|
| - if (_shouldWrapParenthesisBeforeAnd(outerCondition)) {
|
| - outerConditionSource = "(${outerConditionSource})";
|
| - }
|
| - condition = "${outerConditionSource} && ${targetConditionSource}";
|
| - }
|
| - // replace outer "if" statement
|
| - {
|
| - Statement targetThenStatement = targetIfStatement.thenStatement;
|
| - List<Statement> targetThenStatements = getStatements(targetThenStatement);
|
| - SourceRange lineRanges =
|
| - utils.getLinesRangeStatements(targetThenStatements);
|
| - String oldSource = utils.getRangeText(lineRanges);
|
| - String newSource = utils.indentSourceLeftRight(oldSource, false);
|
| - _addReplaceEdit(
|
| - rangeNode(outerIfStatement),
|
| - "if ($condition) {${eol}${newSource}${prefix}}");
|
| - }
|
| - // done
|
| - _addAssist(AssistKind.JOIN_IF_WITH_OUTER, []);
|
| - }
|
| -
|
| - void _addProposal_joinVariableDeclaration_onAssignment() {
|
| - // check that node is LHS in assignment
|
| - if (node is SimpleIdentifier &&
|
| - node.parent is AssignmentExpression &&
|
| - (node.parent as AssignmentExpression).leftHandSide == node &&
|
| - node.parent.parent is ExpressionStatement) {
|
| - } else {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - AssignmentExpression assignExpression = node.parent as AssignmentExpression;
|
| - // check that binary expression is assignment
|
| - if (assignExpression.operator.type != TokenType.EQ) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare "declaration" statement
|
| - Element element = (node as SimpleIdentifier).staticElement;
|
| - if (element == null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - int declOffset = element.nameOffset;
|
| - AstNode declNode = new NodeLocator.con1(declOffset).searchWithin(unit);
|
| - if (declNode != null &&
|
| - declNode.parent is VariableDeclaration &&
|
| - (declNode.parent as VariableDeclaration).name == declNode &&
|
| - declNode.parent.parent is VariableDeclarationList &&
|
| - declNode.parent.parent.parent is VariableDeclarationStatement) {
|
| - } else {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - VariableDeclaration decl = declNode.parent as VariableDeclaration;
|
| - VariableDeclarationStatement declStatement =
|
| - decl.parent.parent as VariableDeclarationStatement;
|
| - // may be has initializer
|
| - if (decl.initializer != null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // check that "declaration" statement declared only one variable
|
| - if (declStatement.variables.variables.length != 1) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // check that the "declaration" and "assignment" statements are
|
| - // parts of the same Block
|
| - ExpressionStatement assignStatement =
|
| - node.parent.parent as ExpressionStatement;
|
| - if (assignStatement.parent is Block &&
|
| - assignStatement.parent == declStatement.parent) {
|
| - } else {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - Block block = assignStatement.parent as Block;
|
| - // check that "declaration" and "assignment" statements are adjacent
|
| - List<Statement> statements = block.statements;
|
| - if (statements.indexOf(assignStatement) ==
|
| - statements.indexOf(declStatement) + 1) {
|
| - } else {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // add edits
|
| - {
|
| - int assignOffset = assignExpression.operator.offset;
|
| - _addReplaceEdit(rangeEndStart(declNode, assignOffset), " ");
|
| - }
|
| - // add proposal
|
| - _addAssist(AssistKind.JOIN_VARIABLE_DECLARATION, []);
|
| - }
|
| -
|
| - void _addProposal_joinVariableDeclaration_onDeclaration() {
|
| - // prepare enclosing VariableDeclarationList
|
| - VariableDeclarationList declList =
|
| - node.getAncestor((node) => node is VariableDeclarationList);
|
| - if (declList != null && declList.variables.length == 1) {
|
| - } else {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - VariableDeclaration decl = declList.variables[0];
|
| - // already initialized
|
| - if (decl.initializer != null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare VariableDeclarationStatement in Block
|
| - if (declList.parent is VariableDeclarationStatement &&
|
| - declList.parent.parent is Block) {
|
| - } else {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - VariableDeclarationStatement declStatement =
|
| - declList.parent as VariableDeclarationStatement;
|
| - Block block = declStatement.parent as Block;
|
| - List<Statement> statements = block.statements;
|
| - // prepare assignment
|
| - AssignmentExpression assignExpression;
|
| - {
|
| - // declaration should not be last Statement
|
| - int declIndex = statements.indexOf(declStatement);
|
| - if (declIndex < statements.length - 1) {
|
| - } else {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // next Statement should be assignment
|
| - Statement assignStatement = statements[declIndex + 1];
|
| - if (assignStatement is ExpressionStatement) {
|
| - } else {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - ExpressionStatement expressionStatement =
|
| - assignStatement as ExpressionStatement;
|
| - // expression should be assignment
|
| - if (expressionStatement.expression is AssignmentExpression) {
|
| - } else {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - assignExpression = expressionStatement.expression as AssignmentExpression;
|
| - }
|
| - // check that pure assignment
|
| - if (assignExpression.operator.type != TokenType.EQ) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // add edits
|
| - {
|
| - int assignOffset = assignExpression.operator.offset;
|
| - _addReplaceEdit(rangeEndStart(decl.name, assignOffset), " ");
|
| - }
|
| - // add proposal
|
| - _addAssist(AssistKind.JOIN_VARIABLE_DECLARATION, []);
|
| - }
|
| -
|
| - void _addProposal_removeTypeAnnotation() {
|
| - AstNode typeStart = null;
|
| - AstNode typeEnd = null;
|
| - // try top-level variable
|
| - {
|
| - TopLevelVariableDeclaration declaration =
|
| - node.getAncestor((node) => node is TopLevelVariableDeclaration);
|
| - if (declaration != null) {
|
| - TypeName typeNode = declaration.variables.type;
|
| - if (typeNode != null) {
|
| - VariableDeclaration field = declaration.variables.variables[0];
|
| - typeStart = declaration;
|
| - typeEnd = field;
|
| - }
|
| - }
|
| - }
|
| - // try class field
|
| - {
|
| - FieldDeclaration fieldDeclaration =
|
| - node.getAncestor((node) => node is FieldDeclaration);
|
| - if (fieldDeclaration != null) {
|
| - TypeName typeNode = fieldDeclaration.fields.type;
|
| - if (typeNode != null) {
|
| - VariableDeclaration field = fieldDeclaration.fields.variables[0];
|
| - typeStart = fieldDeclaration;
|
| - typeEnd = field;
|
| - }
|
| - }
|
| - }
|
| - // try local variable
|
| - {
|
| - VariableDeclarationStatement statement =
|
| - node.getAncestor((node) => node is VariableDeclarationStatement);
|
| - if (statement != null) {
|
| - TypeName typeNode = statement.variables.type;
|
| - if (typeNode != null) {
|
| - VariableDeclaration variable = statement.variables.variables[0];
|
| - typeStart = typeNode;
|
| - typeEnd = variable;
|
| - }
|
| - }
|
| - }
|
| - // add edit
|
| - if (typeStart != null && typeEnd != null) {
|
| - SourceRange typeRange = rangeStartStart(typeStart, typeEnd);
|
| - _addReplaceEdit(typeRange, "var ");
|
| - }
|
| - // add proposal
|
| - _addAssist(AssistKind.REMOVE_TYPE_ANNOTATION, []);
|
| - }
|
| -
|
| - void _addProposal_replaceConditionalWithIfElse() {
|
| - ConditionalExpression conditional = null;
|
| - // may be on Statement with Conditional
|
| - Statement statement = node.getAncestor((node) => node is Statement);
|
| - if (statement == null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // variable declaration
|
| - bool inVariable = false;
|
| - if (statement is VariableDeclarationStatement) {
|
| - VariableDeclarationStatement variableStatement = statement;
|
| - for (VariableDeclaration variable in
|
| - variableStatement.variables.variables) {
|
| - if (variable.initializer is ConditionalExpression) {
|
| - conditional = variable.initializer as ConditionalExpression;
|
| - inVariable = true;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - // assignment
|
| - bool inAssignment = false;
|
| - if (statement is ExpressionStatement) {
|
| - ExpressionStatement exprStmt = statement;
|
| - if (exprStmt.expression is AssignmentExpression) {
|
| - AssignmentExpression assignment =
|
| - exprStmt.expression as AssignmentExpression;
|
| - if (assignment.operator.type == TokenType.EQ &&
|
| - assignment.rightHandSide is ConditionalExpression) {
|
| - conditional = assignment.rightHandSide as ConditionalExpression;
|
| - inAssignment = true;
|
| - }
|
| - }
|
| - }
|
| - // return
|
| - bool inReturn = false;
|
| - if (statement is ReturnStatement) {
|
| - ReturnStatement returnStatement = statement;
|
| - if (returnStatement.expression is ConditionalExpression) {
|
| - conditional = returnStatement.expression as ConditionalExpression;
|
| - inReturn = true;
|
| - }
|
| - }
|
| - // prepare environment
|
| - String indent = utils.getIndent(1);
|
| - String prefix = utils.getNodePrefix(statement);
|
| - // Type v = Conditional;
|
| - if (inVariable) {
|
| - VariableDeclaration variable = conditional.parent as VariableDeclaration;
|
| - _addRemoveEdit(rangeEndEnd(variable.name, conditional));
|
| - String conditionSrc = _getNodeText(conditional.condition);
|
| - String thenSrc = _getNodeText(conditional.thenExpression);
|
| - String elseSrc = _getNodeText(conditional.elseExpression);
|
| - String name = variable.name.name;
|
| - String src = eol;
|
| - src += prefix + 'if ($conditionSrc) {' + eol;
|
| - src += prefix + indent + '$name = $thenSrc;' + eol;
|
| - src += prefix + '} else {' + eol;
|
| - src += prefix + indent + '$name = $elseSrc;' + eol;
|
| - src += prefix + '}';
|
| - _addReplaceEdit(rangeEndLength(statement, 0), src);
|
| - }
|
| - // v = Conditional;
|
| - if (inAssignment) {
|
| - AssignmentExpression assignment =
|
| - conditional.parent as AssignmentExpression;
|
| - Expression leftSide = assignment.leftHandSide;
|
| - String conditionSrc = _getNodeText(conditional.condition);
|
| - String thenSrc = _getNodeText(conditional.thenExpression);
|
| - String elseSrc = _getNodeText(conditional.elseExpression);
|
| - String name = _getNodeText(leftSide);
|
| - String src = '';
|
| - src += 'if ($conditionSrc) {' + eol;
|
| - src += prefix + indent + '$name = $thenSrc;' + eol;
|
| - src += prefix + '} else {' + eol;
|
| - src += prefix + indent + '$name = $elseSrc;' + eol;
|
| - src += prefix + '}';
|
| - _addReplaceEdit(rangeNode(statement), src);
|
| - }
|
| - // return Conditional;
|
| - if (inReturn) {
|
| - String conditionSrc = _getNodeText(conditional.condition);
|
| - String thenSrc = _getNodeText(conditional.thenExpression);
|
| - String elseSrc = _getNodeText(conditional.elseExpression);
|
| - String src = '';
|
| - src += 'if ($conditionSrc) {' + eol;
|
| - src += prefix + indent + 'return $thenSrc;' + eol;
|
| - src += prefix + '} else {' + eol;
|
| - src += prefix + indent + 'return $elseSrc;' + eol;
|
| - src += prefix + '}';
|
| - _addReplaceEdit(rangeNode(statement), src);
|
| - }
|
| - // add proposal
|
| - _addAssist(AssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE, []);
|
| - }
|
| -
|
| - void _addProposal_replaceIfElseWithConditional() {
|
| - // should be "if"
|
| - if (node is! IfStatement) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - IfStatement ifStatement = node as IfStatement;
|
| - // single then/else statements
|
| - Statement thenStatement = getSingleStatement(ifStatement.thenStatement);
|
| - Statement elseStatement = getSingleStatement(ifStatement.elseStatement);
|
| - if (thenStatement == null || elseStatement == null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // returns
|
| - if (thenStatement is ReturnStatement || elseStatement is ReturnStatement) {
|
| - ReturnStatement thenReturn = thenStatement as ReturnStatement;
|
| - ReturnStatement elseReturn = elseStatement as ReturnStatement;
|
| - String conditionSrc = _getNodeText(ifStatement.condition);
|
| - String theSrc = _getNodeText(thenReturn.expression);
|
| - String elseSrc = _getNodeText(elseReturn.expression);
|
| - _addReplaceEdit(
|
| - rangeNode(ifStatement),
|
| - 'return $conditionSrc ? $theSrc : $elseSrc;');
|
| - }
|
| - // assignments -> v = Conditional;
|
| - if (thenStatement is ExpressionStatement &&
|
| - elseStatement is ExpressionStatement) {
|
| - Expression thenExpression = thenStatement.expression;
|
| - Expression elseExpression = elseStatement.expression;
|
| - if (thenExpression is AssignmentExpression &&
|
| - elseExpression is AssignmentExpression) {
|
| - AssignmentExpression thenAssignment = thenExpression;
|
| - AssignmentExpression elseAssignment = elseExpression;
|
| - String thenTarget = _getNodeText(thenAssignment.leftHandSide);
|
| - String elseTarget = _getNodeText(elseAssignment.leftHandSide);
|
| - if (thenAssignment.operator.type == TokenType.EQ &&
|
| - elseAssignment.operator.type == TokenType.EQ &&
|
| - StringUtils.equals(thenTarget, elseTarget)) {
|
| - String conditionSrc = _getNodeText(ifStatement.condition);
|
| - String theSrc = _getNodeText(thenAssignment.rightHandSide);
|
| - String elseSrc = _getNodeText(elseAssignment.rightHandSide);
|
| - _addReplaceEdit(
|
| - rangeNode(ifStatement),
|
| - '$thenTarget = $conditionSrc ? $theSrc : $elseSrc;');
|
| - }
|
| - }
|
| - }
|
| - // add proposal
|
| - _addAssist(AssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL, []);
|
| - }
|
| -
|
| - void _addProposal_splitAndCondition() {
|
| - // check that user invokes quick assist on binary expression
|
| - if (node is! BinaryExpression) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - BinaryExpression binaryExpression = node as BinaryExpression;
|
| - // prepare operator position
|
| - if (!_isOperatorSelected(
|
| - binaryExpression,
|
| - selectionOffset,
|
| - selectionLength)) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // should be &&
|
| - if (binaryExpression.operator.type != TokenType.AMPERSAND_AMPERSAND) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare "if"
|
| - Statement statement = node.getAncestor((node) => node is Statement);
|
| - if (statement is! IfStatement) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - IfStatement ifStatement = statement as IfStatement;
|
| - // check that binary expression is part of first level && condition of "if"
|
| - BinaryExpression condition = binaryExpression;
|
| - while (condition.parent is BinaryExpression &&
|
| - (condition.parent as BinaryExpression).operator.type ==
|
| - TokenType.AMPERSAND_AMPERSAND) {
|
| - condition = condition.parent as BinaryExpression;
|
| - }
|
| - if (ifStatement.condition != condition) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // prepare environment
|
| - String prefix = utils.getNodePrefix(ifStatement);
|
| - String indent = utils.getIndent(1);
|
| - // prepare "rightCondition"
|
| - String rightConditionSource;
|
| - {
|
| - SourceRange rightConditionRange =
|
| - rangeStartEnd(binaryExpression.rightOperand, condition);
|
| - rightConditionSource = _getRangeText(rightConditionRange);
|
| - }
|
| - // remove "&& rightCondition"
|
| - _addRemoveEdit(rangeEndEnd(binaryExpression.leftOperand, condition));
|
| - // update "then" statement
|
| - Statement thenStatement = ifStatement.thenStatement;
|
| - Statement elseStatement = ifStatement.elseStatement;
|
| - if (thenStatement is Block) {
|
| - Block thenBlock = thenStatement;
|
| - SourceRange thenBlockRange = rangeNode(thenBlock);
|
| - // insert inner "if" with right part of "condition"
|
| - {
|
| - String source =
|
| - "${eol}${prefix}${indent}if (${rightConditionSource}) {";
|
| - int thenBlockInsideOffset = thenBlockRange.offset + 1;
|
| - _addInsertEdit(thenBlockInsideOffset, source);
|
| - }
|
| - // insert closing "}" for inner "if"
|
| - {
|
| - int thenBlockEnd = thenBlockRange.end;
|
| - String source = "${indent}}";
|
| - // may be move "else" statements
|
| - if (elseStatement != null) {
|
| - List<Statement> elseStatements = getStatements(elseStatement);
|
| - SourceRange elseLinesRange =
|
| - utils.getLinesRangeStatements(elseStatements);
|
| - String elseIndentOld = "${prefix}${indent}";
|
| - String elseIndentNew = "${elseIndentOld}${indent}";
|
| - String newElseSource =
|
| - utils.replaceSourceRangeIndent(elseLinesRange, elseIndentOld, elseIndentNew);
|
| - // append "else" block
|
| - source += " else {${eol}";
|
| - source += newElseSource;
|
| - source += "${prefix}${indent}}";
|
| - // remove old "else" range
|
| - _addRemoveEdit(rangeStartEnd(thenBlockEnd, elseStatement));
|
| - }
|
| - // insert before outer "then" block "}"
|
| - source += "${eol}${prefix}";
|
| - _addInsertEdit(thenBlockEnd - 1, source);
|
| - }
|
| - } else {
|
| - // insert inner "if" with right part of "condition"
|
| - {
|
| - String source = "${eol}${prefix}${indent}if (${rightConditionSource})";
|
| - _addInsertEdit(ifStatement.rightParenthesis.offset + 1, source);
|
| - }
|
| - // indent "else" statements to correspond inner "if"
|
| - if (elseStatement != null) {
|
| - SourceRange elseRange =
|
| - rangeStartEnd(ifStatement.elseKeyword.offset, elseStatement);
|
| - SourceRange elseLinesRange = utils.getLinesRange(elseRange);
|
| - String elseIndentOld = prefix;
|
| - String elseIndentNew = "${elseIndentOld}${indent}";
|
| - edits.add(
|
| - utils.createIndentEdit(elseLinesRange, elseIndentOld, elseIndentNew));
|
| - }
|
| - }
|
| - // indent "then" statements to correspond inner "if"
|
| - {
|
| - List<Statement> thenStatements = getStatements(thenStatement);
|
| - SourceRange linesRange = utils.getLinesRangeStatements(thenStatements);
|
| - String thenIndentOld = "${prefix}${indent}";
|
| - String thenIndentNew = "${thenIndentOld}${indent}";
|
| - edits.add(
|
| - utils.createIndentEdit(linesRange, thenIndentOld, thenIndentNew));
|
| - }
|
| - // add proposal
|
| - _addAssist(AssistKind.SPLIT_AND_CONDITION, []);
|
| - }
|
| -
|
| - void _addProposal_splitVariableDeclaration() {
|
| - // prepare DartVariableStatement, should be part of Block
|
| - VariableDeclarationStatement statement =
|
| - node.getAncestor((node) => node is VariableDeclarationStatement);
|
| - if (statement != null && statement.parent is Block) {
|
| - } else {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // check that statement declares single variable
|
| - List<VariableDeclaration> variables = statement.variables.variables;
|
| - if (variables.length != 1) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - VariableDeclaration variable = variables[0];
|
| - // prepare initializer
|
| - Expression initializer = variable.initializer;
|
| - if (initializer == null) {
|
| - _coverageMarker();
|
| - return;
|
| - }
|
| - // remove initializer value
|
| - _addRemoveEdit(rangeEndStart(variable.name, statement.semicolon));
|
| - // add assignment statement
|
| - String indent = utils.getNodePrefix(statement);
|
| - String name = variable.name.name;
|
| - String initSrc = _getNodeText(initializer);
|
| - SourceRange assignRange = rangeEndLength(statement, 0);
|
| - _addReplaceEdit(assignRange, eol + indent + name + ' = ' + initSrc + ';');
|
| - // add proposal
|
| - _addAssist(AssistKind.SPLIT_VARIABLE_DECLARATION, []);
|
| - }
|
| -
|
| - void _addProposal_surroundWith() {
|
| - // prepare selected statements
|
| - List<Statement> selectedStatements;
|
| - {
|
| - SourceRange selection =
|
| - rangeStartLength(selectionOffset, selectionLength);
|
| - StatementAnalyzer selectionAnalyzer =
|
| - new StatementAnalyzer(unit, selection);
|
| - unit.accept(selectionAnalyzer);
|
| - List<AstNode> selectedNodes = selectionAnalyzer.selectedNodes;
|
| - // convert nodes to statements
|
| - selectedStatements = [];
|
| - for (AstNode selectedNode in selectedNodes) {
|
| - if (selectedNode is Statement) {
|
| - selectedStatements.add(selectedNode);
|
| - }
|
| - }
|
| - // we want only statements
|
| - if (selectedStatements.isEmpty ||
|
| - selectedStatements.length != selectedNodes.length) {
|
| - return;
|
| - }
|
| - }
|
| - // prepare statement information
|
| - Statement firstStatement = selectedStatements[0];
|
| - Statement lastStatement = selectedStatements[selectedStatements.length - 1];
|
| - SourceRange statementsRange =
|
| - utils.getLinesRangeStatements(selectedStatements);
|
| - // prepare environment
|
| - String indentOld = utils.getNodePrefix(firstStatement);
|
| - String indentNew = "${indentOld}${utils.getIndent(1)}";
|
| - // "block"
|
| - {
|
| - _addInsertEdit(statementsRange.offset, "${indentOld}{${eol}");
|
| - {
|
| - Edit edit =
|
| - utils.createIndentEdit(statementsRange, indentOld, indentNew);
|
| - edits.add(edit);
|
| - }
|
| - _addInsertEdit(statementsRange.end, "${indentOld}}${eol}");
|
| - exitPosition = _newPosition(lastStatement.end);
|
| - // add proposal
|
| - _addAssist(AssistKind.SURROUND_WITH_BLOCK, []);
|
| - }
|
| - // "if"
|
| - {
|
| - {
|
| - int offset = statementsRange.offset;
|
| - SourceBuilder sb = new SourceBuilder(file, offset);
|
| - sb.append(indentOld);
|
| - sb.append("if (");
|
| - {
|
| - sb.startPosition("CONDITION");
|
| - sb.append("condition");
|
| - sb.endPosition();
|
| - }
|
| - sb.append(") {");
|
| - sb.append(eol);
|
| - _insertBuilder(sb);
|
| - }
|
| - {
|
| - Edit edit =
|
| - utils.createIndentEdit(statementsRange, indentOld, indentNew);
|
| - edits.add(edit);
|
| - }
|
| - _addInsertEdit(statementsRange.end, "${indentOld}}${eol}");
|
| - exitPosition = _newPosition(lastStatement.end);
|
| - // add proposal
|
| - _addAssist(AssistKind.SURROUND_WITH_IF, []);
|
| - }
|
| - // "while"
|
| - {
|
| - {
|
| - int offset = statementsRange.offset;
|
| - SourceBuilder sb = new SourceBuilder(file, offset);
|
| - sb.append(indentOld);
|
| - sb.append("while (");
|
| - {
|
| - sb.startPosition("CONDITION");
|
| - sb.append("condition");
|
| - sb.endPosition();
|
| - }
|
| - sb.append(") {");
|
| - sb.append(eol);
|
| - _insertBuilder(sb);
|
| - }
|
| - {
|
| - Edit edit =
|
| - utils.createIndentEdit(statementsRange, indentOld, indentNew);
|
| - edits.add(edit);
|
| - }
|
| - _addInsertEdit(statementsRange.end, "${indentOld}}${eol}");
|
| - exitPosition = _newPosition(lastStatement.end);
|
| - // add proposal
|
| - _addAssist(AssistKind.SURROUND_WITH_WHILE, []);
|
| - }
|
| - // "for-in"
|
| - {
|
| - {
|
| - int offset = statementsRange.offset;
|
| - SourceBuilder sb = new SourceBuilder(file, offset);
|
| - sb.append(indentOld);
|
| - sb.append("for (var ");
|
| - {
|
| - sb.startPosition("NAME");
|
| - sb.append("item");
|
| - sb.endPosition();
|
| - }
|
| - sb.append(" in ");
|
| - {
|
| - sb.startPosition("ITERABLE");
|
| - sb.append("iterable");
|
| - sb.endPosition();
|
| - }
|
| - sb.append(") {");
|
| - sb.append(eol);
|
| - _insertBuilder(sb);
|
| - }
|
| - {
|
| - Edit edit =
|
| - utils.createIndentEdit(statementsRange, indentOld, indentNew);
|
| - edits.add(edit);
|
| - }
|
| - _addInsertEdit(statementsRange.end, "${indentOld}}${eol}");
|
| - exitPosition = _newPosition(lastStatement.end);
|
| - // add proposal
|
| - _addAssist(AssistKind.SURROUND_WITH_FOR_IN, []);
|
| - }
|
| - // "for"
|
| - {
|
| - {
|
| - int offset = statementsRange.offset;
|
| - SourceBuilder sb = new SourceBuilder(file, offset);
|
| - sb.append(indentOld);
|
| - sb.append("for (var ");
|
| - {
|
| - sb.startPosition("VAR");
|
| - sb.append("v");
|
| - sb.endPosition();
|
| - }
|
| - sb.append(" = ");
|
| - {
|
| - sb.startPosition("INIT");
|
| - sb.append("init");
|
| - sb.endPosition();
|
| - }
|
| - sb.append("; ");
|
| - {
|
| - sb.startPosition("CONDITION");
|
| - sb.append("condition");
|
| - sb.endPosition();
|
| - }
|
| - sb.append("; ");
|
| - {
|
| - sb.startPosition("INCREMENT");
|
| - sb.append("increment");
|
| - sb.endPosition();
|
| - }
|
| - sb.append(") {");
|
| - sb.append(eol);
|
| - _insertBuilder(sb);
|
| - }
|
| - {
|
| - Edit edit =
|
| - utils.createIndentEdit(statementsRange, indentOld, indentNew);
|
| - edits.add(edit);
|
| - }
|
| - _addInsertEdit(statementsRange.end, "${indentOld}}${eol}");
|
| - exitPosition = _newPosition(lastStatement.end);
|
| - // add proposal
|
| - _addAssist(AssistKind.SURROUND_WITH_FOR, []);
|
| - }
|
| - // "do-while"
|
| - {
|
| - _addInsertEdit(statementsRange.offset, "${indentOld}do {${eol}");
|
| - {
|
| - Edit edit =
|
| - utils.createIndentEdit(statementsRange, indentOld, indentNew);
|
| - edits.add(edit);
|
| - }
|
| - {
|
| - int offset = statementsRange.end;
|
| - SourceBuilder sb = new SourceBuilder(file, offset);
|
| - sb.append(indentOld);
|
| - sb.append("} while (");
|
| - {
|
| - sb.startPosition("CONDITION");
|
| - sb.append("condition");
|
| - sb.endPosition();
|
| - }
|
| - sb.append(");");
|
| - sb.append(eol);
|
| - _insertBuilder(sb);
|
| - }
|
| - exitPosition = _newPosition(lastStatement.end);
|
| - // add proposal
|
| - _addAssist(AssistKind.SURROUND_WITH_DO_WHILE, []);
|
| - }
|
| - // "try-catch"
|
| - {
|
| - _addInsertEdit(statementsRange.offset, "${indentOld}try {${eol}");
|
| - {
|
| - Edit edit =
|
| - utils.createIndentEdit(statementsRange, indentOld, indentNew);
|
| - edits.add(edit);
|
| - }
|
| - {
|
| - int offset = statementsRange.end;
|
| - SourceBuilder sb = new SourceBuilder(file, offset);
|
| - sb.append(indentOld);
|
| - sb.append("} on ");
|
| - {
|
| - sb.startPosition("EXCEPTION_TYPE");
|
| - sb.append("Exception");
|
| - sb.endPosition();
|
| - }
|
| - sb.append(" catch (");
|
| - {
|
| - sb.startPosition("EXCEPTION_VAR");
|
| - sb.append("e");
|
| - sb.endPosition();
|
| - }
|
| - sb.append(") {");
|
| - sb.append(eol);
|
| - //
|
| - sb.append(indentNew);
|
| - {
|
| - sb.startPosition("CATCH");
|
| - sb.append("// TODO");
|
| - sb.endPosition();
|
| - sb.setExitOffset();
|
| - }
|
| - sb.append(eol);
|
| - //
|
| - sb.append(indentOld);
|
| - sb.append("}");
|
| - sb.append(eol);
|
| - //
|
| - _insertBuilder(sb);
|
| - exitPosition = _newPosition(sb.exitOffset);
|
| - }
|
| - // add proposal
|
| - _addAssist(AssistKind.SURROUND_WITH_TRY_CATCH, []);
|
| - }
|
| - // "try-finally"
|
| - {
|
| - _addInsertEdit(statementsRange.offset, "${indentOld}try {${eol}");
|
| - {
|
| - Edit edit =
|
| - utils.createIndentEdit(statementsRange, indentOld, indentNew);
|
| - edits.add(edit);
|
| - }
|
| - {
|
| - int offset = statementsRange.end;
|
| - SourceBuilder sb = new SourceBuilder(file, offset);
|
| - //
|
| - sb.append(indentOld);
|
| - sb.append("} finally {");
|
| - sb.append(eol);
|
| - //
|
| - sb.append(indentNew);
|
| - {
|
| - sb.startPosition("FINALLY");
|
| - sb.append("// TODO");
|
| - sb.endPosition();
|
| - }
|
| - sb.setExitOffset();
|
| - sb.append(eol);
|
| - //
|
| - sb.append(indentOld);
|
| - sb.append("}");
|
| - sb.append(eol);
|
| - //
|
| - _insertBuilder(sb);
|
| - exitPosition = _newPosition(sb.exitOffset);
|
| - }
|
| - // add proposal
|
| - _addAssist(AssistKind.SURROUND_WITH_TRY_FINALLY, []);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Adds a new [Edit] to [edits].
|
| - */
|
| - void _addRemoveEdit(SourceRange range) {
|
| - _addReplaceEdit(range, '');
|
| - }
|
| -
|
| - /**
|
| - * Adds a new [Edit] to [edits].
|
| - */
|
| - void _addReplaceEdit(SourceRange range, String text) {
|
| - Edit edit = new Edit(range.offset, range.length, text);
|
| - edits.add(edit);
|
| - }
|
| -
|
| - /**
|
| - * Returns an existing or just added [LinkedEditGroup] with [groupId].
|
| - */
|
| - LinkedEditGroup _getLinkedPosition(String groupId) {
|
| - LinkedEditGroup group = linkedPositionGroups[groupId];
|
| - if (group == null) {
|
| - group = new LinkedEditGroup(groupId);
|
| - linkedPositionGroups[groupId] = group;
|
| - }
|
| - return group;
|
| - }
|
| -
|
| - /**
|
| - * Returns the text of the given node in the unit.
|
| - */
|
| - String _getNodeText(AstNode node) {
|
| - return utils.getNodeText(node);
|
| - }
|
| -
|
| - /**
|
| - * Returns the text of the given range in the unit.
|
| - */
|
| - String _getRangeText(SourceRange range) {
|
| - return utils.getRangeText(range);
|
| - }
|
| -
|
| - /**
|
| - * Inserts the given [SourceBuilder] at its offset.
|
| - */
|
| - void _insertBuilder(SourceBuilder builder) {
|
| - String text = builder.toString();
|
| - _addInsertEdit(builder.offset, text);
|
| - // add linked positions
|
| - builder.linkedPositionGroups.forEach((LinkedEditGroup group) {
|
| - LinkedEditGroup fixGroup = _getLinkedPosition(group.id);
|
| - group.positions.forEach((Position position) {
|
| - fixGroup.addPosition(position, group.length);
|
| - });
|
| - group.suggestions.forEach((LinkedEditSuggestion suggestion) {
|
| - fixGroup.addSuggestion(suggestion);
|
| - });
|
| - });
|
| - }
|
| -
|
| - Position _newPosition(int offset) {
|
| - return new Position(file, offset);
|
| - }
|
| -
|
| - /**
|
| - * This method does nothing, but we invoke it in places where Dart VM
|
| - * coverage agent fails to provide coverage information - such as almost
|
| - * all "return" statements.
|
| - *
|
| - * https://code.google.com/p/dart/issues/detail?id=19912
|
| - */
|
| - static void _coverageMarker() {
|
| - }
|
| -
|
| - /**
|
| - * Returns `true` if the selection covers an operator of the given
|
| - * [BinaryExpression].
|
| - */
|
| - static bool _isOperatorSelected(BinaryExpression binaryExpression, int offset,
|
| - int length) {
|
| - AstNode left = binaryExpression.leftOperand;
|
| - AstNode right = binaryExpression.rightOperand;
|
| - // between the nodes
|
| - if (offset >= left.endToken.end && offset + length <= right.offset) {
|
| - _coverageMarker();
|
| - return true;
|
| - }
|
| - // or exactly select the node (but not with infix expressions)
|
| - if (offset == left.offset && offset + length == right.endToken.end) {
|
| - if (left is BinaryExpression || right is BinaryExpression) {
|
| - _coverageMarker();
|
| - return false;
|
| - }
|
| - _coverageMarker();
|
| - return true;
|
| - }
|
| - // invalid selection (part of node, etc)
|
| - _coverageMarker();
|
| - return false;
|
| - }
|
| -
|
| - /**
|
| - * Checks if the given [Expression] should be wrapped with parenthesis when we
|
| - * want to use it as operand of a logical `and` expression.
|
| - */
|
| - static bool _shouldWrapParenthesisBeforeAnd(Expression expr) {
|
| - if (expr is BinaryExpression) {
|
| - BinaryExpression binary = expr;
|
| - int precedence = binary.operator.type.precedence;
|
| - return precedence < TokenClass.LOGICAL_AND_OPERATOR.precedence;
|
| - }
|
| - return false;
|
| - }
|
| -}
|
| -
|
| -
|
| -class _SimpleIdentifierRecursiveAstVisitor extends RecursiveAstVisitor {
|
| - final _SimpleIdentifierVisitor visitor;
|
| -
|
| - _SimpleIdentifierRecursiveAstVisitor(this.visitor);
|
| -
|
| - @override
|
| - visitSimpleIdentifier(SimpleIdentifier node) {
|
| - visitor(node);
|
| - }
|
| -}
|
|
|