| Index: pkg/analysis_server/lib/src/services/generated/util.dart
|
| diff --git a/pkg/analysis_server/lib/src/services/generated/util.dart b/pkg/analysis_server/lib/src/services/generated/util.dart
|
| deleted file mode 100644
|
| index 31a15c3025e5ef441b18dcfca89e3be66d7f1d8e..0000000000000000000000000000000000000000
|
| --- a/pkg/analysis_server/lib/src/services/generated/util.dart
|
| +++ /dev/null
|
| @@ -1,1833 +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.
|
| -
|
| -// This code was auto-generated, is not intended to be edited, and is subject to
|
| -// significant change. Please see the README file for more information.
|
| -
|
| -library services.util;
|
| -
|
| -import 'dart:collection';
|
| -import "dart:math" as math;
|
| -
|
| -import 'package:analyzer/src/generated/java_core.dart' hide StringUtils;
|
| -import 'package:analyzer/src/generated/ast.dart';
|
| -import 'package:analyzer/src/generated/element.dart';
|
| -import 'package:analyzer/src/generated/engine.dart';
|
| -import 'package:analyzer/src/generated/error.dart';
|
| -import 'package:analyzer/src/generated/resolver.dart';
|
| -import 'package:analyzer/src/generated/source.dart';
|
| -import 'package:analyzer/src/generated/scanner.dart';
|
| -
|
| -import 'stubs.dart';
|
| -
|
| -/**
|
| - * Context for which assistance should be provided.
|
| - */
|
| -class AssistContext {
|
| - final SearchEngine searchEngine;
|
| -
|
| - final AnalysisContext analysisContext;
|
| -
|
| - final String analysisContextId;
|
| -
|
| - final Source source;
|
| -
|
| - final CompilationUnit compilationUnit;
|
| -
|
| - final int selectionOffset;
|
| -
|
| - final int selectionLength;
|
| -
|
| - AstNode _coveredNode;
|
| -
|
| - AstNode _coveringNode;
|
| -
|
| - Element _coveredElement;
|
| -
|
| - bool _coveredElementFound = false;
|
| -
|
| - AssistContext.con1(this.searchEngine, this.analysisContext,
|
| - this.analysisContextId, this.source, this.compilationUnit,
|
| - this.selectionOffset, this.selectionLength);
|
| -
|
| - AssistContext.con2(SearchEngine searchEngine, AnalysisContext analysisContext,
|
| - String analysisContextId, Source source, CompilationUnit compilationUnit,
|
| - SourceRange selectionRange)
|
| - : this.con1(searchEngine, analysisContext, analysisContextId, source,
|
| - compilationUnit, selectionRange.offset, selectionRange.length);
|
| -
|
| - /**
|
| - * @return the resolved [CompilationUnitElement] of the [Source].
|
| - */
|
| - CompilationUnitElement get compilationUnitElement => compilationUnit.element;
|
| -
|
| - /**
|
| - * @return the [Element] of the [coveredNode], may be <code>null</code>.
|
| - */
|
| - Element get coveredElement {
|
| - if (!_coveredElementFound) {
|
| - _coveredElementFound = true;
|
| - AstNode coveredNode = this.coveredNode;
|
| - if (coveredNode == null) {
|
| - return null;
|
| - }
|
| - _coveredElement =
|
| - ElementLocator.locateWithOffset(coveredNode, selectionOffset);
|
| - }
|
| - return _coveredElement;
|
| - }
|
| -
|
| - /**
|
| - * @return the [AstNode] that is covered by the selection.
|
| - */
|
| - AstNode get coveredNode {
|
| - if (_coveredNode == null) {
|
| - NodeLocator locator = new NodeLocator(selectionOffset, selectionOffset);
|
| - _coveredNode = locator.searchWithin(compilationUnit);
|
| - }
|
| - return _coveredNode;
|
| - }
|
| -
|
| - /**
|
| - * @return the ASTNode that covers the selection.
|
| - */
|
| - AstNode get coveringNode {
|
| - if (_coveringNode == null) {
|
| - NodeLocator locator =
|
| - new NodeLocator(selectionOffset, selectionOffset + selectionLength);
|
| - _coveringNode = locator.searchWithin(compilationUnit);
|
| - }
|
| - return _coveringNode;
|
| - }
|
| -
|
| - /**
|
| - * @return the errors associated with the [Source].
|
| - */
|
| - List<AnalysisError> get errors {
|
| - Source source = this.source;
|
| - if (analysisContext == null || source == null) {
|
| - return AnalysisError.NO_ERRORS;
|
| - }
|
| - return analysisContext.getErrors(source).errors;
|
| - }
|
| -
|
| - /**
|
| - * @return the [SourceRange] of the selection.
|
| - */
|
| - SourceRange get selectionRange =>
|
| - new SourceRange(selectionOffset, selectionLength);
|
| -}
|
| -
|
| -/**
|
| - * Utilities for analyzing [CompilationUnit], its parts and source.
|
| - */
|
| -class CorrectionUtils {
|
| - static List<String> _KNOWN_METHOD_NAME_PREFIXES = ["get", "is", "to"];
|
| -
|
| - /**
|
| - * @return <code>true</code> if given [List]s are equals at given position.
|
| - */
|
| - static bool allListsEqual(List<List> lists, int position) {
|
| - Object element = lists[0][position];
|
| - for (List list in lists) {
|
| - if (!identical(list[position], element)) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - /**
|
| - * @return <code>true</code> if given [SourceRange] covers given [AstNode].
|
| - */
|
| - static bool covers(SourceRange r, AstNode node) {
|
| - SourceRange nodeRange = SourceRangeFactory.rangeNode(node);
|
| - return r.covers(nodeRange);
|
| - }
|
| -
|
| - /**
|
| - * @return all direct children of the given [Element].
|
| - */
|
| - static List<Element> getChildren(Element parent) =>
|
| - getChildren2(parent, null);
|
| -
|
| - /**
|
| - * @param name the required name of children; may be <code>null</code> to get children with any
|
| - * name.
|
| - * @return all direct children of the given [Element], with given name.
|
| - */
|
| - static List<Element> getChildren2(Element parent, String name) {
|
| - List<Element> children = [];
|
| - parent.accept(new GeneralizingElementVisitor_CorrectionUtils_getChildren(
|
| - parent, name, children));
|
| - return children;
|
| - }
|
| -
|
| - static String getDefaultValueCode(DartType type) {
|
| - if (type != null) {
|
| - String typeName = type.displayName;
|
| - if (typeName == "bool") {
|
| - return "false";
|
| - }
|
| - if (typeName == "int") {
|
| - return "0";
|
| - }
|
| - if (typeName == "double") {
|
| - return "0.0";
|
| - }
|
| - if (typeName == "String") {
|
| - return "''";
|
| - }
|
| - }
|
| - // no better guess
|
| - return "null";
|
| - }
|
| -
|
| - /**
|
| - * @return the name of the [Element] kind.
|
| - */
|
| - static String getElementKindName(Element element) {
|
| - ElementKind kind = element.kind;
|
| - return getElementKindName2(kind);
|
| - }
|
| -
|
| - /**
|
| - * @return the display name of the [ElementKind].
|
| - */
|
| - static String getElementKindName2(ElementKind kind) => kind.displayName;
|
| -
|
| - /**
|
| - * @return the human name of the [Element].
|
| - */
|
| - static String getElementQualifiedName(Element element) {
|
| - ElementKind kind = element.kind;
|
| - while (true) {
|
| - if (kind == ElementKind.FIELD || kind == ElementKind.METHOD) {
|
| - return "${element.enclosingElement.displayName}.${element.displayName}";
|
| - } else {
|
| - return element.displayName;
|
| - }
|
| - break;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * @return the [ExecutableElement] of the enclosing executable [AstNode].
|
| - */
|
| - static ExecutableElement getEnclosingExecutableElement(AstNode node) {
|
| - while (node != null) {
|
| - if (node is FunctionDeclaration) {
|
| - return node.element;
|
| - }
|
| - if (node is ConstructorDeclaration) {
|
| - return node.element;
|
| - }
|
| - if (node is MethodDeclaration) {
|
| - return node.element;
|
| - }
|
| - node = node.parent;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * @return the enclosing executable [AstNode].
|
| - */
|
| - static AstNode getEnclosingExecutableNode(AstNode node) {
|
| - while (node != null) {
|
| - if (node is FunctionDeclaration) {
|
| - return node;
|
| - }
|
| - if (node is ConstructorDeclaration) {
|
| - return node;
|
| - }
|
| - if (node is MethodDeclaration) {
|
| - return node;
|
| - }
|
| - node = node.parent;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * @return [Element] exported from the given [LibraryElement].
|
| - */
|
| - static Element getExportedElement(LibraryElement library, String name) {
|
| - if (library == null) {
|
| - return null;
|
| - }
|
| - return getExportNamespace2(library)[name];
|
| - }
|
| -
|
| - /**
|
| - * TODO(scheglov) may be replace with some API for this
|
| - *
|
| - * @return the namespace of the given [ExportElement].
|
| - */
|
| - static Map<String, Element> getExportNamespace(ExportElement exp) {
|
| - Namespace namespace =
|
| - new NamespaceBuilder().createExportNamespaceForDirective(exp);
|
| - return namespace.definedNames;
|
| - }
|
| -
|
| - /**
|
| - * TODO(scheglov) may be replace with some API for this
|
| - *
|
| - * @return the export namespace of the given [LibraryElement].
|
| - */
|
| - static Map<String, Element> getExportNamespace2(LibraryElement library) {
|
| - Namespace namespace =
|
| - new NamespaceBuilder().createExportNamespaceForLibrary(library);
|
| - return namespace.definedNames;
|
| - }
|
| -
|
| - /**
|
| - * @return [getExpressionPrecedence] for parent node, or `0` if parent node
|
| - * is [ParenthesizedExpression]. The reason is that `(expr)` is always
|
| - * executed after `expr`.
|
| - */
|
| - static int getExpressionParentPrecedence(AstNode node) {
|
| - AstNode parent = node.parent;
|
| - if (parent is ParenthesizedExpression) {
|
| - return 0;
|
| - }
|
| - return getExpressionPrecedence(parent);
|
| - }
|
| -
|
| - /**
|
| - * Return the precedence of the given [node]: the result of invoking
|
| - * [Expression.precedence] if the node is an [Expression], or a negative value
|
| - * otherwise.
|
| - */
|
| - static int getExpressionPrecedence(AstNode node) {
|
| - if (node is Expression) {
|
| - return node.precedence;
|
| - }
|
| - return -1000;
|
| - }
|
| -
|
| - /**
|
| - * TODO(scheglov) may be replace with some API for this
|
| - *
|
| - * @return the namespace of the given [ImportElement].
|
| - */
|
| - static Map<String, Element> getImportNamespace(ImportElement imp) {
|
| - Namespace namespace =
|
| - new NamespaceBuilder().createImportNamespaceForDirective(imp);
|
| - return namespace.definedNames;
|
| - }
|
| -
|
| - /**
|
| - * @return all [CompilationUnitElement] the given [LibraryElement] consists of.
|
| - */
|
| - static List<CompilationUnitElement> getLibraryUnits(LibraryElement library) {
|
| - List<CompilationUnitElement> units = [];
|
| - units.add(library.definingCompilationUnit);
|
| - units.addAll(library.parts);
|
| - return units;
|
| - }
|
| -
|
| - /**
|
| - * @return the line prefix from the given source, i.e. basically just whitespace prefix of the
|
| - * given [String].
|
| - */
|
| - static String getLinesPrefix(String lines) {
|
| - int index = 0;
|
| - while (index < lines.length) {
|
| - int c = lines.codeUnitAt(index);
|
| - if (!Character.isWhitespace(c)) {
|
| - break;
|
| - }
|
| - index++;
|
| - }
|
| - return lines.substring(0, index);
|
| - }
|
| -
|
| - /**
|
| - * @return the [LocalVariableElement] or [ParameterElement] if given
|
| - * [SimpleIdentifier] is the reference to local variable or parameter, or
|
| - * <code>null</code> in the other case.
|
| - */
|
| - static VariableElement getLocalOrParameterVariableElement(
|
| - SimpleIdentifier node) {
|
| - Element element = node.staticElement;
|
| - if (element is LocalVariableElement) {
|
| - return element;
|
| - }
|
| - if (element is ParameterElement) {
|
| - return element;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * @return the [LocalVariableElement] if given [SimpleIdentifier] is the reference to
|
| - * local variable, or <code>null</code> in the other case.
|
| - */
|
| - static LocalVariableElement getLocalVariableElement(SimpleIdentifier node) {
|
| - Element element = node.staticElement;
|
| - if (element is LocalVariableElement) {
|
| - return element;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * @return the nearest common ancestor [AstNode] of the given [AstNode]s.
|
| - */
|
| - static AstNode getNearestCommonAncestor(List<AstNode> nodes) {
|
| - // may be no nodes
|
| - if (nodes.isEmpty) {
|
| - return null;
|
| - }
|
| - // prepare parents
|
| - List<List<AstNode>> parents = [];
|
| - for (AstNode node in nodes) {
|
| - parents.add(getParents(node));
|
| - }
|
| - // find min length
|
| - int minLength = 2147483647;
|
| - for (List<AstNode> parentList in parents) {
|
| - minLength = math.min(minLength, parentList.length);
|
| - }
|
| - // find deepest parent
|
| - int i = 0;
|
| - for (; i < minLength; i++) {
|
| - if (!allListsEqual(parents, i)) {
|
| - break;
|
| - }
|
| - }
|
| - return parents[0][i - 1];
|
| - }
|
| -
|
| - /**
|
| - * @return the [Expression] qualified if given node is name part of a [PropertyAccess]
|
| - * or [PrefixedIdentifier]. May be <code>null</code>.
|
| - */
|
| - static Expression getNodeQualifier(SimpleIdentifier node) {
|
| - AstNode parent = node.parent;
|
| - if (parent is PropertyAccess) {
|
| - PropertyAccess propertyAccess = parent;
|
| - if (identical(propertyAccess.propertyName, node)) {
|
| - return propertyAccess.target;
|
| - }
|
| - }
|
| - if (parent is PrefixedIdentifier) {
|
| - PrefixedIdentifier prefixed = parent;
|
| - if (identical(prefixed.identifier, node)) {
|
| - return prefixed.prefix;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * @return the [ParameterElement] if given [SimpleIdentifier] is the reference to
|
| - * parameter, or <code>null</code> in the other case.
|
| - */
|
| - static ParameterElement getParameterElement(SimpleIdentifier node) {
|
| - Element element = node.staticElement;
|
| - if (element is ParameterElement) {
|
| - return element;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * Return the precedence of the given [expression]'s parent. May be `-1` no
|
| - * operator.
|
| - *
|
| - * See [getPrecedence].
|
| - */
|
| - static int getParentPrecedence(Expression expression) {
|
| - AstNode parent = expression.parent;
|
| - if (parent is Expression) {
|
| - return getPrecedence(parent);
|
| - }
|
| - return -1;
|
| - }
|
| -
|
| - /**
|
| - * @return parent [AstNode]s from [CompilationUnit] (at index "0") to the given one.
|
| - */
|
| - static List<AstNode> getParents(AstNode node) {
|
| - // prepare number of parents
|
| - int numParents = 0;
|
| - {
|
| - AstNode current = node.parent;
|
| - while (current != null) {
|
| - numParents++;
|
| - current = current.parent;
|
| - }
|
| - }
|
| - // fill array of parents
|
| - List<AstNode> parents = new List<AstNode>(numParents);
|
| - AstNode current = node.parent;
|
| - int index = numParents;
|
| - while (current != null) {
|
| - parents[--index] = current;
|
| - current = current.parent;
|
| - }
|
| - return parents;
|
| - }
|
| -
|
| - /**
|
| - * @return the precedence of the given [Expression] operator. May be
|
| - * `Integer#MAX_VALUE` if not an operator.
|
| - */
|
| - static int getPrecedence(Expression expression) {
|
| - if (expression is BinaryExpression) {
|
| - BinaryExpression binaryExpression = expression;
|
| - return binaryExpression.operator.type.precedence;
|
| - }
|
| - if (expression is PrefixExpression) {
|
| - PrefixExpression prefixExpression = expression;
|
| - return prefixExpression.operator.type.precedence;
|
| - }
|
| - if (expression is PostfixExpression) {
|
| - PostfixExpression postfixExpression = expression;
|
| - return postfixExpression.operator.type.precedence;
|
| - }
|
| - return 2147483647;
|
| - }
|
| -
|
| - /**
|
| - * @return the [PropertyAccessorElement] if given [SimpleIdentifier] is the reference
|
| - * to property, or <code>null</code> in the other case.
|
| - */
|
| - static PropertyAccessorElement getPropertyAccessorElement(
|
| - SimpleIdentifier node) {
|
| - Element element = node.staticElement;
|
| - if (element is PropertyAccessorElement) {
|
| - return element;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * If given [AstNode] is name of qualified property extraction, returns target from which
|
| - * this property is extracted. Otherwise `null`.
|
| - */
|
| - static Expression getQualifiedPropertyTarget(AstNode node) {
|
| - AstNode parent = node.parent;
|
| - if (parent is PrefixedIdentifier) {
|
| - PrefixedIdentifier prefixed = parent;
|
| - if (identical(prefixed.identifier, node)) {
|
| - return parent.prefix;
|
| - }
|
| - }
|
| - if (parent is PropertyAccess) {
|
| - PropertyAccess access = parent;
|
| - if (identical(access.propertyName, node)) {
|
| - return access.realTarget;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * Returns the name of the file which corresponds to the name of the class according to the style
|
| - * guide. However class does not have to be in this file.
|
| - */
|
| - static String getRecommentedFileNameForClass(String className) {
|
| - int len = className.length;
|
| - StringBuffer buffer = new StringBuffer();
|
| - bool prevWasUpper = false;
|
| - for (int i = 0; i < len; i++) {
|
| - int c = className.codeUnitAt(i);
|
| - if (Character.isUpperCase(c)) {
|
| - bool nextIsUpper =
|
| - i < len - 1 && Character.isUpperCase(className.codeUnitAt(i + 1));
|
| - if (i == 0) {} else if (prevWasUpper) {
|
| - // HTTPServer
|
| - // ^
|
| - if (!nextIsUpper) {
|
| - buffer.writeCharCode(0x5F);
|
| - }
|
| - } else {
|
| - // HttpServer
|
| - // ^
|
| - buffer.writeCharCode(0x5F);
|
| - }
|
| - prevWasUpper = true;
|
| - c = Character.toLowerCase(c);
|
| - } else {
|
| - prevWasUpper = false;
|
| - }
|
| - buffer.writeCharCode(c);
|
| - }
|
| - buffer.write(".dart");
|
| - String fileName = buffer.toString();
|
| - return fileName;
|
| - }
|
| -
|
| - /**
|
| - * @return given [Statement] if not [Block], first child [Statement] if
|
| - * [Block], or <code>null</code> if more than one child.
|
| - */
|
| - static Statement getSingleStatement(Statement statement) {
|
| - if (statement is Block) {
|
| - List<Statement> blockStatements = statement.statements;
|
| - if (blockStatements.length != 1) {
|
| - return null;
|
| - }
|
| - return blockStatements[0];
|
| - }
|
| - return statement;
|
| - }
|
| -
|
| - /**
|
| - * @return the [String] content of the given [Source].
|
| - */
|
| - static String getSourceContent(AnalysisContext context, Source source) =>
|
| - context.getContents(source).data.toString();
|
| -
|
| - /**
|
| - * @return given [Statement] if not [Block], all children [Statement]s if
|
| - * [Block].
|
| - */
|
| - static List<Statement> getStatements(Statement statement) {
|
| - if (statement is Block) {
|
| - return statement.statements;
|
| - }
|
| - return [];
|
| - }
|
| -
|
| - /**
|
| - * @return all top-level elements declared in the given [LibraryElement].
|
| - */
|
| - static List<Element> getTopLevelElements(LibraryElement library) {
|
| - List<Element> elements = [];
|
| - List<CompilationUnitElement> units = getLibraryUnits(library);
|
| - for (CompilationUnitElement unit in units) {
|
| - elements.addAll(unit.functions);
|
| - elements.addAll(unit.functionTypeAliases);
|
| - elements.addAll(unit.types);
|
| - elements.addAll(unit.topLevelVariables);
|
| - }
|
| - return elements;
|
| - }
|
| -
|
| - /**
|
| - * @return the possible names for variable with initializer of the given [StringLiteral].
|
| - */
|
| - static List<String> getVariableNameSuggestions(
|
| - String text, Set<String> excluded) {
|
| - // filter out everything except of letters and white spaces
|
| - {
|
| - StringBuffer buffer = new StringBuffer();
|
| - for (int i = 0; i < text.length; i++) {
|
| - int c = text.codeUnitAt(i);
|
| - if (Character.isLetter(c) || Character.isWhitespace(c)) {
|
| - buffer.writeCharCode(c);
|
| - }
|
| - }
|
| - text = buffer.toString();
|
| - }
|
| - // make single camel-case text
|
| - {
|
| - List<String> words = StringUtils.split(text);
|
| - StringBuffer buffer = new StringBuffer();
|
| - for (int i = 0; i < words.length; i++) {
|
| - String word = words[i];
|
| - if (i > 0) {
|
| - word = StringUtils.capitalize(word);
|
| - }
|
| - buffer.write(word);
|
| - }
|
| - text = buffer.toString();
|
| - }
|
| - // split camel-case into separate suggested names
|
| - Set<String> res = new LinkedHashSet();
|
| - _addAll(excluded, res, _getVariableNameSuggestions(text));
|
| - return new List.from(res);
|
| - }
|
| -
|
| - /**
|
| - * @return the possible names for variable with given expected type and expression.
|
| - */
|
| - static List<String> getVariableNameSuggestions2(DartType expectedType,
|
| - Expression assignedExpression, Set<String> excluded) {
|
| - Set<String> res = new LinkedHashSet();
|
| - // use expression
|
| - if (assignedExpression != null) {
|
| - String nameFromExpression =
|
| - _getBaseNameFromExpression(assignedExpression);
|
| - if (nameFromExpression != null) {
|
| - nameFromExpression = StringUtils.removeStart(nameFromExpression, "_");
|
| - _addAll(excluded, res, _getVariableNameSuggestions(nameFromExpression));
|
| - }
|
| - String nameFromParent =
|
| - _getBaseNameFromLocationInParent(assignedExpression);
|
| - if (nameFromParent != null) {
|
| - _addAll(excluded, res, _getVariableNameSuggestions(nameFromParent));
|
| - }
|
| - }
|
| - // use type
|
| - if (expectedType != null && !expectedType.isDynamic) {
|
| - String typeName = expectedType.name;
|
| - if ("int" == typeName) {
|
| - _addSingleCharacterName(excluded, res, 0x69);
|
| - } else if ("double" == typeName) {
|
| - _addSingleCharacterName(excluded, res, 0x64);
|
| - } else if ("String" == typeName) {
|
| - _addSingleCharacterName(excluded, res, 0x73);
|
| - } else {
|
| - _addAll(excluded, res, _getVariableNameSuggestions(typeName));
|
| - }
|
| - res.remove(typeName);
|
| - }
|
| - // done
|
| - return new List.from(res);
|
| - }
|
| -
|
| - /**
|
| - * Return `true` if the given [element]'s display name ([Element.displayName])
|
| - * is equal to the given [name].
|
| - */
|
| - static bool hasDisplayName(Element element, String name) {
|
| - if (element == null) {
|
| - return false;
|
| - }
|
| - String elementDisplayName = element.displayName;
|
| - return StringUtils.equals(elementDisplayName, name);
|
| - }
|
| -
|
| - /**
|
| - * Return `true` if the given [element]'s name ([Element.name]) is equal to
|
| - * the given [name].
|
| - */
|
| - static bool hasName(Element element, String name) {
|
| - if (element == null) {
|
| - return false;
|
| - }
|
| - String elementName = element.name;
|
| - return StringUtils.equals(elementName, name);
|
| - }
|
| -
|
| - /**
|
| - * @return `true` if the given [SimpleIdentifier] is the name of the
|
| - * [NamedExpression].
|
| - */
|
| - static bool isNamedExpressionName(SimpleIdentifier node) {
|
| - AstNode parent = node.parent;
|
| - if (parent is Label) {
|
| - Label label = parent;
|
| - if (identical(label.label, node)) {
|
| - AstNode parent2 = label.parent;
|
| - if (parent2 is NamedExpression) {
|
| - return identical(parent2.name, label);
|
| - }
|
| - }
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - /**
|
| - * Adds "toAdd" items which are not excluded.
|
| - */
|
| - static void _addAll(
|
| - Set<String> excluded, Set<String> result, Iterable<String> toAdd) {
|
| - for (String item in toAdd) {
|
| - // add name based on "item", but not "excluded"
|
| - for (int suffix = 1;; suffix++) {
|
| - // prepare name, just "item" or "item2", "item3", etc
|
| - String name = item;
|
| - if (suffix > 1) {
|
| - name += suffix.toString();
|
| - }
|
| - // add once found not excluded
|
| - if (!excluded.contains(name)) {
|
| - result.add(name);
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Add to "result" then given "c" or the first ASCII character after it.
|
| - */
|
| - static void _addSingleCharacterName(
|
| - Set<String> excluded, Set<String> result, int c) {
|
| - while (c < 0x7A) {
|
| - String name = new String.fromCharCode(c);
|
| - // may be done
|
| - if (!excluded.contains(name)) {
|
| - result.add(name);
|
| - break;
|
| - }
|
| - // next character
|
| - c = (c + 1);
|
| - }
|
| - }
|
| -
|
| - static String _getBaseNameFromExpression(Expression expression) {
|
| - String name = null;
|
| - // e as Type
|
| - if (expression is AsExpression) {
|
| - AsExpression asExpression = expression as AsExpression;
|
| - expression = asExpression.expression;
|
| - }
|
| - // analyze expressions
|
| - if (expression is SimpleIdentifier) {
|
| - SimpleIdentifier node = expression;
|
| - return node.name;
|
| - } else if (expression is PrefixedIdentifier) {
|
| - PrefixedIdentifier node = expression;
|
| - return node.identifier.name;
|
| - } else if (expression is MethodInvocation) {
|
| - name = expression.methodName.name;
|
| - } else if (expression is InstanceCreationExpression) {
|
| - InstanceCreationExpression creation = expression;
|
| - ConstructorName constructorName = creation.constructorName;
|
| - TypeName typeName = constructorName.type;
|
| - if (typeName != null) {
|
| - Identifier typeNameIdentifier = typeName.name;
|
| - // new ClassName()
|
| - if (typeNameIdentifier is SimpleIdentifier) {
|
| - return typeNameIdentifier.name;
|
| - }
|
| - // new prefix.name();
|
| - if (typeNameIdentifier is PrefixedIdentifier) {
|
| - PrefixedIdentifier prefixed = typeNameIdentifier;
|
| - // new prefix.ClassName()
|
| - if (prefixed.prefix.staticElement is PrefixElement) {
|
| - return prefixed.identifier.name;
|
| - }
|
| - // new ClassName.constructorName()
|
| - return prefixed.prefix.name;
|
| - }
|
| - }
|
| - }
|
| - // strip known prefixes
|
| - if (name != null) {
|
| - for (int i = 0; i < _KNOWN_METHOD_NAME_PREFIXES.length; i++) {
|
| - String curr = _KNOWN_METHOD_NAME_PREFIXES[i];
|
| - if (name.startsWith(curr)) {
|
| - if (name == curr) {
|
| - return null;
|
| - } else if (Character.isUpperCase(name.codeUnitAt(curr.length))) {
|
| - return name.substring(curr.length);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - // done
|
| - return name;
|
| - }
|
| -
|
| - static String _getBaseNameFromLocationInParent(Expression expression) {
|
| - // value in named expression
|
| - if (expression.parent is NamedExpression) {
|
| - NamedExpression namedExpression = expression.parent as NamedExpression;
|
| - if (identical(namedExpression.expression, expression)) {
|
| - return namedExpression.name.label.name;
|
| - }
|
| - }
|
| - // positional argument
|
| - {
|
| - ParameterElement parameter = expression.propagatedParameterElement;
|
| - if (parameter == null) {
|
| - parameter = expression.staticParameterElement;
|
| - }
|
| - if (parameter != null) {
|
| - return parameter.displayName;
|
| - }
|
| - }
|
| - // unknown
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * @return [Expression]s from <code>operands</code> which are completely covered by given
|
| - * [SourceRange]. Range should start and end between given [Expression]s.
|
| - */
|
| - static List<Expression> _getOperandsForSourceRange(
|
| - List<Expression> operands, SourceRange range) {
|
| - assert(!operands.isEmpty);
|
| - List<Expression> subOperands = [];
|
| - // track range enter/exit
|
| - bool entered = false;
|
| - bool exited = false;
|
| - // may be range starts before or on first operand
|
| - if (range.offset <= operands[0].offset) {
|
| - entered = true;
|
| - }
|
| - // iterate over gaps between operands
|
| - for (int i = 0; i < operands.length - 1; i++) {
|
| - Expression operand = operands[i];
|
| - Expression nextOperand = operands[i + 1];
|
| - SourceRange inclusiveGap =
|
| - SourceRangeFactory.rangeEndStart(operand, nextOperand).getMoveEnd(1);
|
| - // add operand, if already entered range
|
| - if (entered) {
|
| - subOperands.add(operand);
|
| - // may be last operand in range
|
| - if (range.endsIn(inclusiveGap)) {
|
| - exited = true;
|
| - }
|
| - } else {
|
| - // may be first operand in range
|
| - if (range.startsIn(inclusiveGap)) {
|
| - entered = true;
|
| - }
|
| - }
|
| - }
|
| - // check if last operand is in range
|
| - Expression lastGroupMember = operands[operands.length - 1];
|
| - if (range.end == lastGroupMember.end) {
|
| - subOperands.add(lastGroupMember);
|
| - exited = true;
|
| - }
|
| - // we expect that range covers only given operands
|
| - if (!exited) {
|
| - return [];
|
| - }
|
| - // done
|
| - return subOperands;
|
| - }
|
| -
|
| - /**
|
| - * @return all operands of the given [BinaryExpression] and its children with the same
|
| - * operator.
|
| - */
|
| - static List<Expression> _getOperandsInOrderFor(BinaryExpression groupRoot) {
|
| - List<Expression> operands = [];
|
| - TokenType groupOperatorType = groupRoot.operator.type;
|
| - groupRoot.accept(
|
| - new GeneralizingAstVisitor_CorrectionUtils_getOperandsInOrderFor(
|
| - groupOperatorType, operands));
|
| - return operands;
|
| - }
|
| -
|
| - /**
|
| - * @return all variants of names by removing leading words by one.
|
| - */
|
| - static List<String> _getVariableNameSuggestions(String name) {
|
| - List<String> result = [];
|
| - List<String> parts =
|
| - name.split("(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])");
|
| - for (int i = 0; i < parts.length; i++) {
|
| - String suggestion =
|
| - "${parts[i].toLowerCase()}${StringUtils.join(parts, "", i + 1, parts.length)}";
|
| - result.add(suggestion);
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - final CompilationUnit unit;
|
| -
|
| - LibraryElement _library;
|
| -
|
| - String _buffer;
|
| -
|
| - String _endOfLine;
|
| -
|
| - CorrectionUtils(this.unit) {
|
| - CompilationUnitElement element = unit.element;
|
| - this._library = element.library;
|
| - this._buffer = getSourceContent(element.context, element.source);
|
| - }
|
| -
|
| - /**
|
| - * @return the [AstNode] that encloses the given offset.
|
| - */
|
| - AstNode findNode(int offset) => new NodeLocator(offset).searchWithin(unit);
|
| -
|
| - /**
|
| - * TODO(scheglov) replace with nodes once there will be [CompilationUnit.comments].
|
| - *
|
| - * @return the [SourceRange]s of all comments in [CompilationUnit].
|
| - */
|
| - List<SourceRange> get commentRanges {
|
| - List<SourceRange> ranges = [];
|
| - Token token = unit.beginToken;
|
| - while (token != null && token.type != TokenType.EOF) {
|
| - Token commentToken = token.precedingComments;
|
| - while (commentToken != null) {
|
| - ranges.add(SourceRangeFactory.rangeToken(commentToken));
|
| - commentToken = commentToken.next;
|
| - }
|
| - token = token.next;
|
| - }
|
| - return ranges;
|
| - }
|
| -
|
| - /**
|
| - * @return the EOL to use for this [CompilationUnit].
|
| - */
|
| - String get endOfLine {
|
| - if (_endOfLine == null) {
|
| - if (_buffer.contains("\r\n")) {
|
| - _endOfLine = "\r\n";
|
| - } else {
|
| - _endOfLine = "\n";
|
| - }
|
| - }
|
| - return _endOfLine;
|
| - }
|
| -
|
| - /**
|
| - * @return the default indentation with given level.
|
| - */
|
| - String getIndent(int level) => StringUtils.repeat(" ", level);
|
| -
|
| - /**
|
| - * @return the source of the given [SourceRange] with indentation changed from "oldIndent"
|
| - * to "newIndent", keeping indentation of the lines relative to each other.
|
| - */
|
| - String getIndentSource(
|
| - SourceRange range, String oldIndent, String newIndent) {
|
| - String oldSource = getText3(range);
|
| - return getIndentSource3(oldSource, oldIndent, newIndent);
|
| - }
|
| -
|
| - /**
|
| - * Indents given source left or right.
|
| - *
|
| - * @return the source with changed indentation.
|
| - */
|
| - String getIndentSource2(String source, bool right) {
|
| - StringBuffer buffer = new StringBuffer();
|
| - String indent = getIndent(1);
|
| - String eol = endOfLine;
|
| - List<String> lines =
|
| - StringUtils.splitByWholeSeparatorPreserveAllTokens(source, eol);
|
| - for (int i = 0; i < lines.length; i++) {
|
| - String line = lines[i];
|
| - // last line, stop if empty
|
| - if (i == lines.length - 1 && StringUtils.isEmpty(line)) {
|
| - break;
|
| - }
|
| - // update line
|
| - if (right) {
|
| - line = "${indent}${line}";
|
| - } else {
|
| - line = StringUtils.removeStart(line, indent);
|
| - }
|
| - // append line
|
| - buffer.write(line);
|
| - buffer.write(eol);
|
| - }
|
| - return buffer.toString();
|
| - }
|
| -
|
| - /**
|
| - * @return the source with indentation changed from "oldIndent" to "newIndent", keeping
|
| - * indentation of the lines relative to each other.
|
| - */
|
| - String getIndentSource3(String source, String oldIndent, String newIndent) {
|
| - // prepare STRING token ranges
|
| - List<SourceRange> lineRanges = [];
|
| - for (Token token in TokenUtils.getTokens(source)) {
|
| - if (token.type == TokenType.STRING) {
|
| - lineRanges.add(SourceRangeFactory.rangeToken(token));
|
| - }
|
| - }
|
| - // re-indent lines
|
| - StringBuffer buffer = new StringBuffer();
|
| - String eol = endOfLine;
|
| - List<String> lines =
|
| - StringUtils.splitByWholeSeparatorPreserveAllTokens(source, eol);
|
| - int lineOffset = 0;
|
| - for (int i = 0; i < lines.length; i++) {
|
| - String line = lines[i];
|
| - // last line, stop if empty
|
| - if (i == lines.length - 1 && StringUtils.isEmpty(line)) {
|
| - break;
|
| - }
|
| - // check if "offset" is in one of the String ranges
|
| - bool inString = false;
|
| - for (SourceRange lineRange in lineRanges) {
|
| - if (lineOffset > lineRange.offset && lineOffset < lineRange.end) {
|
| - inString = true;
|
| - }
|
| - if (lineOffset > lineRange.end) {
|
| - break;
|
| - }
|
| - }
|
| - lineOffset += line.length + eol.length;
|
| - // update line indent
|
| - if (!inString) {
|
| - line = "${newIndent}${StringUtils.removeStart(line, oldIndent)}";
|
| - }
|
| - // append line
|
| - buffer.write(line);
|
| - buffer.write(eol);
|
| - }
|
| - return buffer.toString();
|
| - }
|
| -
|
| - /**
|
| - * @return [InsertDesc], description where to insert new library-related directive.
|
| - */
|
| - CorrectionUtils_InsertDesc get insertDescImport {
|
| - // analyze directives
|
| - Directive prevDirective = null;
|
| - for (Directive directive in unit.directives) {
|
| - if (directive is LibraryDirective ||
|
| - directive is ImportDirective ||
|
| - directive is ExportDirective) {
|
| - prevDirective = directive;
|
| - }
|
| - }
|
| - // insert after last library-related directive
|
| - if (prevDirective != null) {
|
| - CorrectionUtils_InsertDesc result = new CorrectionUtils_InsertDesc();
|
| - result.offset = prevDirective.end;
|
| - String eol = endOfLine;
|
| - if (prevDirective is LibraryDirective) {
|
| - result.prefix = "${eol}${eol}";
|
| - } else {
|
| - result.prefix = eol;
|
| - }
|
| - return result;
|
| - }
|
| - // no directives, use "top" location
|
| - return insertDescTop;
|
| - }
|
| -
|
| - /**
|
| - * @return [InsertDesc], description where to insert new 'part 'directive.
|
| - */
|
| - CorrectionUtils_InsertDesc get insertDescPart {
|
| - // analyze directives
|
| - Directive prevDirective = null;
|
| - for (Directive directive in unit.directives) {
|
| - prevDirective = directive;
|
| - }
|
| - // insert after last directive
|
| - if (prevDirective != null) {
|
| - CorrectionUtils_InsertDesc result = new CorrectionUtils_InsertDesc();
|
| - result.offset = prevDirective.end;
|
| - String eol = endOfLine;
|
| - if (prevDirective is PartDirective) {
|
| - result.prefix = eol;
|
| - } else {
|
| - result.prefix = "${eol}${eol}";
|
| - }
|
| - return result;
|
| - }
|
| - // no directives, use "top" location
|
| - return insertDescTop;
|
| - }
|
| -
|
| - /**
|
| - * @return [InsertDesc], description where to insert new directive or top-level declaration
|
| - * at the top of file.
|
| - */
|
| - CorrectionUtils_InsertDesc get insertDescTop {
|
| - // skip leading line comments
|
| - int offset = 0;
|
| - bool insertEmptyLineBefore = false;
|
| - bool insertEmptyLineAfter = false;
|
| - String source = text;
|
| - // skip hash-bang
|
| - if (offset < source.length - 2) {
|
| - String linePrefix = getText2(offset, 2);
|
| - if (linePrefix == "#!") {
|
| - insertEmptyLineBefore = true;
|
| - offset = getLineNext(offset);
|
| - // skip empty lines to first line comment
|
| - int emptyOffset = offset;
|
| - while (emptyOffset < source.length - 2) {
|
| - int nextLineOffset = getLineNext(emptyOffset);
|
| - String line = source.substring(emptyOffset, nextLineOffset);
|
| - if (line.trim().isEmpty) {
|
| - emptyOffset = nextLineOffset;
|
| - continue;
|
| - } else if (line.startsWith("//")) {
|
| - offset = emptyOffset;
|
| - break;
|
| - } else {
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - // skip line comments
|
| - while (offset < source.length - 2) {
|
| - String linePrefix = getText2(offset, 2);
|
| - if (linePrefix == "//") {
|
| - insertEmptyLineBefore = true;
|
| - offset = getLineNext(offset);
|
| - } else {
|
| - break;
|
| - }
|
| - }
|
| - // determine if empty line is required after
|
| - int nextLineOffset = getLineNext(offset);
|
| - String insertLine = source.substring(offset, nextLineOffset);
|
| - if (!insertLine.trim().isEmpty) {
|
| - insertEmptyLineAfter = true;
|
| - }
|
| - // fill InsertDesc
|
| - CorrectionUtils_InsertDesc desc = new CorrectionUtils_InsertDesc();
|
| - desc.offset = offset;
|
| - if (insertEmptyLineBefore) {
|
| - desc.prefix = endOfLine;
|
| - }
|
| - if (insertEmptyLineAfter) {
|
| - desc.suffix = endOfLine;
|
| - }
|
| - return desc;
|
| - }
|
| -
|
| - /**
|
| - * Skips whitespace characters and single EOL on the right from the given position. If from
|
| - * statement or method end, then this is in the most cases start of the next line.
|
| - */
|
| - int getLineContentEnd(int index) {
|
| - int length = _buffer.length;
|
| - // skip whitespace characters
|
| - while (index < length) {
|
| - int c = _buffer.codeUnitAt(index);
|
| - if (!Character.isWhitespace(c) || c == 0xD || c == 0xA) {
|
| - break;
|
| - }
|
| - index++;
|
| - }
|
| - // skip single \r
|
| - if (index < length && _buffer.codeUnitAt(index) == 0xD) {
|
| - index++;
|
| - }
|
| - // skip single \n
|
| - if (index < length && _buffer.codeUnitAt(index) == 0xA) {
|
| - index++;
|
| - }
|
| - // done
|
| - return index;
|
| - }
|
| -
|
| - /**
|
| - * @return the index of the last space or tab on the left from the given one, if from statement or
|
| - * method start, then this is in most cases start of the line.
|
| - */
|
| - int getLineContentStart(int index) {
|
| - while (index > 0) {
|
| - int c = _buffer.codeUnitAt(index - 1);
|
| - if (c != 0x20 && c != 0x9) {
|
| - break;
|
| - }
|
| - index--;
|
| - }
|
| - return index;
|
| - }
|
| -
|
| - /**
|
| - * @return the start index of the next line after the line which contains given index.
|
| - */
|
| - int getLineNext(int index) {
|
| - int length = _buffer.length;
|
| - // skip to the end of the line
|
| - while (index < length) {
|
| - int c = _buffer.codeUnitAt(index);
|
| - if (c == 0xD || c == 0xA) {
|
| - break;
|
| - }
|
| - index++;
|
| - }
|
| - // skip single \r
|
| - if (index < length && _buffer.codeUnitAt(index) == 0xD) {
|
| - index++;
|
| - }
|
| - // skip single \n
|
| - if (index < length && _buffer.codeUnitAt(index) == 0xA) {
|
| - index++;
|
| - }
|
| - // done
|
| - return index;
|
| - }
|
| -
|
| - /**
|
| - * @return the whitespace prefix of the line which contains given offset.
|
| - */
|
| - String getLinePrefix(int index) {
|
| - int lineStart = getLineThis(index);
|
| - int length = _buffer.length;
|
| - int lineNonWhitespace = lineStart;
|
| - while (lineNonWhitespace < length) {
|
| - int c = _buffer.codeUnitAt(lineNonWhitespace);
|
| - if (c == 0xD || c == 0xA) {
|
| - break;
|
| - }
|
| - if (!Character.isWhitespace(c)) {
|
| - break;
|
| - }
|
| - lineNonWhitespace++;
|
| - }
|
| - return getText2(lineStart, lineNonWhitespace - lineStart);
|
| - }
|
| -
|
| - /**
|
| - * @return the [getLinesRange] for given [Statement]s.
|
| - */
|
| - SourceRange getLinesRange(List<Statement> statements) {
|
| - SourceRange range = SourceRangeFactory.rangeNodes(statements);
|
| - return getLinesRange2(range);
|
| - }
|
| -
|
| - /**
|
| - * @return the [SourceRange] which starts at the start of the line of "offset" and ends at
|
| - * the start of the next line after "end" of the given [SourceRange], i.e. basically
|
| - * complete lines of the source for given [SourceRange].
|
| - */
|
| - SourceRange getLinesRange2(SourceRange range) {
|
| - // start
|
| - int startOffset = range.offset;
|
| - int startLineOffset = getLineContentStart(startOffset);
|
| - // end
|
| - int endOffset = range.end;
|
| - int afterEndLineOffset = getLineContentEnd(endOffset);
|
| - // range
|
| - return SourceRangeFactory.rangeStartEnd(
|
| - startLineOffset, afterEndLineOffset);
|
| - }
|
| -
|
| - /**
|
| - * @return the [getLinesRange] for given [Statement]s.
|
| - */
|
| - SourceRange getLinesRange3(List<Statement> statements) => getLinesRange([]);
|
| -
|
| - /**
|
| - * @return the start index of the line which contains given index.
|
| - */
|
| - int getLineThis(int index) {
|
| - while (index > 0) {
|
| - int c = _buffer.codeUnitAt(index - 1);
|
| - if (c == 0xD || c == 0xA) {
|
| - break;
|
| - }
|
| - index--;
|
| - }
|
| - return index;
|
| - }
|
| -
|
| - /**
|
| - * @return the line prefix consisting of spaces and tabs on the left from the given
|
| - * [AstNode].
|
| - */
|
| - String getNodePrefix(AstNode node) {
|
| - int offset = node.offset;
|
| - // function literal is special, it uses offset of enclosing line
|
| - if (node is FunctionExpression) {
|
| - return getLinePrefix(offset);
|
| - }
|
| - // use just prefix directly before node
|
| - return getPrefix(offset);
|
| - }
|
| -
|
| - /**
|
| - * @return the index of the first non-whitespace character after given index.
|
| - */
|
| - int getNonWhitespaceForward(int index) {
|
| - int length = _buffer.length;
|
| - // skip whitespace characters
|
| - while (index < length) {
|
| - int c = _buffer.codeUnitAt(index);
|
| - if (!Character.isWhitespace(c)) {
|
| - break;
|
| - }
|
| - index++;
|
| - }
|
| - // done
|
| - return index;
|
| - }
|
| -
|
| - /**
|
| - * @return the source for the parameter with the given type and name.
|
| - */
|
| - String getParameterSource(DartType type, String name) {
|
| - // no type
|
| - if (type == null || type.isDynamic) {
|
| - return name;
|
| - }
|
| - // function type
|
| - if (type is FunctionType) {
|
| - FunctionType functionType = type;
|
| - StringBuffer buffer = new StringBuffer();
|
| - // return type
|
| - DartType returnType = functionType.returnType;
|
| - if (returnType != null && !returnType.isDynamic) {
|
| - buffer.write(getTypeSource2(returnType));
|
| - buffer.writeCharCode(0x20);
|
| - }
|
| - // parameter name
|
| - buffer.write(name);
|
| - // parameters
|
| - buffer.writeCharCode(0x28);
|
| - List<ParameterElement> fParameters = functionType.parameters;
|
| - for (int i = 0; i < fParameters.length; i++) {
|
| - ParameterElement fParameter = fParameters[i];
|
| - if (i != 0) {
|
| - buffer.write(", ");
|
| - }
|
| - buffer.write(getParameterSource(fParameter.type, fParameter.name));
|
| - }
|
| - buffer.writeCharCode(0x29);
|
| - // done
|
| - return buffer.toString();
|
| - }
|
| - // simple type
|
| - return "${getTypeSource2(type)} ${name}";
|
| - }
|
| -
|
| - /**
|
| - * @return the line prefix consisting of spaces and tabs on the left from the given offset.
|
| - */
|
| - String getPrefix(int endIndex) {
|
| - int startIndex = getLineContentStart(endIndex);
|
| - return _buffer.substring(startIndex, endIndex);
|
| - }
|
| -
|
| - /**
|
| - * @return the full text of unit.
|
| - */
|
| - String get text => _buffer;
|
| -
|
| - /**
|
| - * @return the given range of text from unit.
|
| - */
|
| - String getText(AstNode node) => getText2(node.offset, node.length);
|
| -
|
| - /**
|
| - * @return the given range of text from unit.
|
| - */
|
| - String getText2(int offset, int length) =>
|
| - _buffer.substring(offset, offset + length);
|
| -
|
| - /**
|
| - * @return the given range of text from unit.
|
| - */
|
| - String getText3(SourceRange range) => getText2(range.offset, range.length);
|
| -
|
| - /**
|
| - * @return the actual type source of the given [Expression], may be `null` if can not
|
| - * be resolved, should be treated as <code>Dynamic</code>.
|
| - */
|
| - String getTypeSource(Expression expression) {
|
| - if (expression == null) {
|
| - return null;
|
| - }
|
| - DartType type = expression.bestType;
|
| - String typeSource = getTypeSource2(type);
|
| - if ("dynamic" == typeSource) {
|
| - return null;
|
| - }
|
| - return typeSource;
|
| - }
|
| -
|
| - /**
|
| - * @return the source to reference the given [Type] in this [CompilationUnit].
|
| - */
|
| - String getTypeSource2(DartType type) {
|
| - StringBuffer buffer = new StringBuffer();
|
| - // prepare element
|
| - Element element = type.element;
|
| - if (element == null) {
|
| - String source = type.toString();
|
| - source = StringUtils.remove(source, "<dynamic>");
|
| - source = StringUtils.remove(source, "<dynamic, dynamic>");
|
| - return source;
|
| - }
|
| - // append prefix
|
| - {
|
| - ImportElement imp = _getImportElement(element);
|
| - if (imp != null && imp.prefix != null) {
|
| - buffer.write(imp.prefix.displayName);
|
| - buffer.write(".");
|
| - }
|
| - }
|
| - // append simple name
|
| - String name = element.displayName;
|
| - buffer.write(name);
|
| - // may be type arguments
|
| - if (type is InterfaceType) {
|
| - InterfaceType interfaceType = type;
|
| - List<DartType> arguments = interfaceType.typeArguments;
|
| - // check if has arguments
|
| - bool hasArguments = false;
|
| - for (DartType argument in arguments) {
|
| - if (!argument.isDynamic) {
|
| - hasArguments = true;
|
| - break;
|
| - }
|
| - }
|
| - // append type arguments
|
| - if (hasArguments) {
|
| - buffer.write("<");
|
| - for (int i = 0; i < arguments.length; i++) {
|
| - DartType argument = arguments[i];
|
| - if (i != 0) {
|
| - buffer.write(", ");
|
| - }
|
| - buffer.write(getTypeSource2(argument));
|
| - }
|
| - buffer.write(">");
|
| - }
|
| - }
|
| - // done
|
| - return buffer.toString();
|
| - }
|
| -
|
| - /**
|
| - * @return <code>true</code> if selection range contains only whitespace.
|
| - */
|
| - bool isJustWhitespace(SourceRange range) =>
|
| - getText3(range).trim().length == 0;
|
| -
|
| - /**
|
| - * @return <code>true</code> if selection range contains only whitespace or comments
|
| - */
|
| - bool isJustWhitespaceOrComment(SourceRange range) {
|
| - String trimmedText = getText3(range).trim();
|
| - // may be whitespace
|
| - if (trimmedText.isEmpty) {
|
| - return true;
|
| - }
|
| - // may be comment
|
| - return TokenUtils.getTokens(trimmedText).isEmpty;
|
| - }
|
| -
|
| - /**
|
| - * @return <code>true</code> if "selection" covers "node" and there are any non-whitespace tokens
|
| - * between "selection" and "node" start/end.
|
| - */
|
| - bool selectionIncludesNonWhitespaceOutsideNode(
|
| - SourceRange selection, AstNode node) =>
|
| - _selectionIncludesNonWhitespaceOutsideRange(
|
| - selection, SourceRangeFactory.rangeNode(node));
|
| -
|
| - /**
|
| - * @return <code>true</code> if given range of [BinaryExpression] can be extracted.
|
| - */
|
| - bool validateBinaryExpressionRange(
|
| - BinaryExpression binaryExpression, SourceRange range) {
|
| - // only parts of associative expression are safe to extract
|
| - if (!binaryExpression.operator.type.isAssociativeOperator) {
|
| - return false;
|
| - }
|
| - // prepare selected operands
|
| - List<Expression> operands = _getOperandsInOrderFor(binaryExpression);
|
| - List<Expression> subOperands = _getOperandsForSourceRange(operands, range);
|
| - // if empty, then something wrong with selection
|
| - if (subOperands.isEmpty) {
|
| - return false;
|
| - }
|
| - // may be some punctuation included into selection - operators, braces, etc
|
| - if (_selectionIncludesNonWhitespaceOutsideOperands(range, subOperands)) {
|
| - return false;
|
| - }
|
| - // OK
|
| - return true;
|
| - }
|
| -
|
| - /**
|
| - * @return the [ImportElement] used to import given [Element] into [library].
|
| - * May be `null` if was not imported, i.e. declared in the same library.
|
| - */
|
| - ImportElement _getImportElement(Element element) {
|
| - for (ImportElement imp in _library.imports) {
|
| - Map<String, Element> definedNames = getImportNamespace(imp);
|
| - if (definedNames.containsValue(element)) {
|
| - return imp;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - bool _selectionIncludesNonWhitespaceOutsideOperands(
|
| - SourceRange selection, List<Expression> operands) =>
|
| - _selectionIncludesNonWhitespaceOutsideRange(
|
| - selection, SourceRangeFactory.rangeNodes(operands));
|
| -
|
| - /**
|
| - * @return <code>true</code> if "selection" covers "range" and there are any non-whitespace tokens
|
| - * between "selection" and "range" start/end.
|
| - */
|
| - bool _selectionIncludesNonWhitespaceOutsideRange(
|
| - SourceRange selection, SourceRange range) {
|
| - // selection should cover range
|
| - if (!selection.covers(range)) {
|
| - return false;
|
| - }
|
| - // non-whitespace between selection start and range start
|
| - if (!isJustWhitespaceOrComment(
|
| - SourceRangeFactory.rangeStartStart(selection, range))) {
|
| - return true;
|
| - }
|
| - // non-whitespace after range
|
| - if (!isJustWhitespaceOrComment(
|
| - SourceRangeFactory.rangeEndEnd(range, selection))) {
|
| - return true;
|
| - }
|
| - // only whitespace in selection around range
|
| - return false;
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Describes where to insert new directive or top-level declaration.
|
| - */
|
| -class CorrectionUtils_InsertDesc {
|
| - int offset = 0;
|
| -
|
| - String prefix = "";
|
| -
|
| - String suffix = "";
|
| -}
|
| -
|
| -class GeneralizingAstVisitor_CorrectionUtils_getOperandsInOrderFor
|
| - extends GeneralizingAstVisitor<Object> {
|
| - TokenType groupOperatorType;
|
| -
|
| - List<Expression> operands;
|
| -
|
| - GeneralizingAstVisitor_CorrectionUtils_getOperandsInOrderFor(
|
| - this.groupOperatorType, this.operands)
|
| - : super();
|
| -
|
| - @override
|
| - Object visitExpression(Expression node) {
|
| - if (node is BinaryExpression && node.operator.type == groupOperatorType) {
|
| - return super.visitNode(node);
|
| - }
|
| - operands.add(node);
|
| - return null;
|
| - }
|
| -}
|
| -
|
| -class GeneralizingElementVisitor_CorrectionUtils_getChildren
|
| - extends GeneralizingElementVisitor<Object> {
|
| - Element parent;
|
| -
|
| - String name;
|
| -
|
| - List<Element> children;
|
| -
|
| - GeneralizingElementVisitor_CorrectionUtils_getChildren(
|
| - this.parent, this.name, this.children)
|
| - : super();
|
| -
|
| - @override
|
| - Object visitElement(Element element) {
|
| - if (identical(element, parent)) {
|
| - super.visitElement(element);
|
| - } else if (name == null || CorrectionUtils.hasDisplayName(element, name)) {
|
| - children.add(element);
|
| - }
|
| - return null;
|
| - }
|
| -}
|
| -
|
| -class GeneralizingElementVisitor_HierarchyUtils_getDirectMembers
|
| - extends GeneralizingElementVisitor<Object> {
|
| - ClassElement clazz;
|
| -
|
| - bool includeSynthetic = false;
|
| -
|
| - List<Element> members;
|
| -
|
| - GeneralizingElementVisitor_HierarchyUtils_getDirectMembers(
|
| - this.clazz, this.includeSynthetic, this.members)
|
| - : super();
|
| -
|
| - @override
|
| - Object visitElement(Element element) {
|
| - if (identical(element, clazz)) {
|
| - return super.visitElement(element);
|
| - }
|
| - if (!includeSynthetic && element.isSynthetic) {
|
| - return null;
|
| - }
|
| - if (element is ConstructorElement) {
|
| - return null;
|
| - }
|
| - if (element is ExecutableElement) {
|
| - members.add(element);
|
| - }
|
| - if (element is FieldElement) {
|
| - members.add(element);
|
| - }
|
| - return null;
|
| - }
|
| -}
|
| -
|
| -class NameOccurrencesFinder extends RecursiveAstVisitor<Object> {
|
| - static Iterable<AstNode> findIn(SimpleIdentifier ident, AstNode root) {
|
| - if (ident == null || ident.bestElement == null) {
|
| - return new Set<AstNode>();
|
| - }
|
| - NameOccurrencesFinder finder = new NameOccurrencesFinder(ident.bestElement);
|
| - root.accept(finder);
|
| - return finder.matches;
|
| - }
|
| -
|
| - Element _target;
|
| -
|
| - Element _target2;
|
| -
|
| - Element _target3;
|
| -
|
| - Element _target4;
|
| -
|
| - Set<AstNode> _matches;
|
| -
|
| - NameOccurrencesFinder(Element source) {
|
| - this._target = source;
|
| - while (true) {
|
| - if (source.kind == ElementKind.GETTER ||
|
| - source.kind == ElementKind.SETTER) {
|
| - PropertyAccessorElement accessorElem =
|
| - source as PropertyAccessorElement;
|
| - this._target2 = accessorElem.variable;
|
| - if (source is Member) {
|
| - Member member = source;
|
| - this._target4 = member.baseElement;
|
| - }
|
| - if (this._target2 is Member) {
|
| - Member member = source as Member;
|
| - this._target3 = member.baseElement;
|
| - }
|
| - } else if (source.kind == ElementKind.FIELD ||
|
| - source.kind == ElementKind.TOP_LEVEL_VARIABLE) {
|
| - PropertyInducingElement propertyElem =
|
| - source as PropertyInducingElement;
|
| - this._target2 = propertyElem.getter;
|
| - this._target3 = propertyElem.setter;
|
| - } else if (source.kind == ElementKind.METHOD) {
|
| - if (source is Member) {
|
| - Member member = source;
|
| - this._target4 = member.baseElement;
|
| - }
|
| - } else if (source.kind == ElementKind.PARAMETER) {
|
| - ParameterElement param = source as ParameterElement;
|
| - if (param.isInitializingFormal) {
|
| - FieldFormalParameterElement fieldInit =
|
| - param as FieldFormalParameterElement;
|
| - this._target2 = fieldInit.field;
|
| - }
|
| - } else {}
|
| - break;
|
| - }
|
| - if (_target2 == null) {
|
| - _target2 = _target;
|
| - }
|
| - if (_target3 == null) {
|
| - _target3 = _target;
|
| - }
|
| - if (_target4 == null) {
|
| - _target4 = _target;
|
| - }
|
| - this._matches = new Set<AstNode>();
|
| - }
|
| -
|
| - Iterable<AstNode> get matches => _matches;
|
| -
|
| - @override
|
| - Object visitSimpleIdentifier(SimpleIdentifier node) {
|
| - Element element = node.bestElement;
|
| - if (element == null) {
|
| - return null;
|
| - }
|
| - _match(element, node);
|
| - if (element is Member) {
|
| - Member member = element;
|
| - _match(member.baseElement, node);
|
| - }
|
| - while (true) {
|
| - if (element.kind == ElementKind.GETTER ||
|
| - element.kind == ElementKind.SETTER) {
|
| - PropertyAccessorElement accessorElem =
|
| - element as PropertyAccessorElement;
|
| - _match(accessorElem.variable, node);
|
| - } else if (element.kind == ElementKind.FIELD ||
|
| - element.kind == ElementKind.TOP_LEVEL_VARIABLE) {
|
| - PropertyInducingElement propertyElem =
|
| - element as PropertyInducingElement;
|
| - _match(propertyElem.getter, node);
|
| - _match(propertyElem.setter, node);
|
| - } else if (element.kind == ElementKind.PARAMETER) {
|
| - ParameterElement param = element as ParameterElement;
|
| - if (param.isInitializingFormal) {
|
| - FieldFormalParameterElement fieldInit =
|
| - param as FieldFormalParameterElement;
|
| - _match(fieldInit.field, node);
|
| - }
|
| - } else {}
|
| - break;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - void _match(Element element, AstNode node) {
|
| - if (identical(_target, element) ||
|
| - identical(_target2, element) ||
|
| - identical(_target3, element) ||
|
| - identical(_target4, element)) {
|
| - _matches.add(node);
|
| - }
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Utilities to work with [Token]s.
|
| - */
|
| -class TokenUtils {
|
| - /**
|
| - * @return the first [KeywordToken] with given [Keyword], may be <code>null</code> if
|
| - * not found.
|
| - */
|
| - static KeywordToken findKeywordToken(List<Token> tokens, Keyword keyword) {
|
| - for (Token token in tokens) {
|
| - if (token is KeywordToken) {
|
| - KeywordToken keywordToken = token;
|
| - if (keywordToken.keyword == keyword) {
|
| - return keywordToken;
|
| - }
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * @return the first [Token] with given [TokenType], may be <code>null</code> if not
|
| - * found.
|
| - */
|
| - static Token findToken(List<Token> tokens, TokenType type) {
|
| - for (Token token in tokens) {
|
| - if (token.type == type) {
|
| - return token;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * @return [Token]s of the given Dart source, not <code>null</code>, may be empty if no
|
| - * tokens or some exception happens.
|
| - */
|
| - static List<Token> getTokens(String s) {
|
| - try {
|
| - List<Token> tokens = [];
|
| - Scanner scanner = new Scanner(null, new CharSequenceReader(s), null);
|
| - Token token = scanner.tokenize();
|
| - while (token.type != TokenType.EOF) {
|
| - tokens.add(token);
|
| - token = token.next;
|
| - }
|
| - return tokens;
|
| - } catch (e) {
|
| - return [];
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * @return <code>true</code> if given [Token]s contain only single [Token] with given
|
| - * [TokenType].
|
| - */
|
| - static bool hasOnly(List<Token> tokens, TokenType type) =>
|
| - tokens.length == 1 && tokens[0].type == type;
|
| -}
|
|
|