Chromium Code Reviews| Index: pkg/analysis_services/lib/src/correction/util.dart |
| diff --git a/pkg/analysis_services/lib/src/correction/util.dart b/pkg/analysis_services/lib/src/correction/util.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a01d36dfb0d3b0bda088b63d0399700465bb3c13 |
| --- /dev/null |
| +++ b/pkg/analysis_services/lib/src/correction/util.dart |
| @@ -0,0 +1,282 @@ |
| +// 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.src.correction.util; |
| + |
| +import 'package:analysis_services/src/correction/source_range.dart'; |
| +import 'package:analysis_services/src/correction/strings.dart'; |
| +import 'package:analyzer/src/generated/ast.dart'; |
| +import 'package:analyzer/src/generated/element.dart'; |
| +import 'package:analyzer/src/generated/resolver.dart'; |
| +import 'package:analyzer/src/generated/source.dart'; |
| + |
| + |
| +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"; |
| +} |
| + |
| + |
| +/** |
| + * Returns [getExpressionPrecedence] for the parent of [node], |
| + * or `0` if the parent node is [ParenthesizedExpression]. |
| + * |
| + * The reason is that `(expr)` is always executed after `expr`. |
| + */ |
| +int getExpressionParentPrecedence(AstNode node) { |
| + AstNode parent = node.parent; |
| + if (parent is ParenthesizedExpression) { |
| + return 0; |
| + } |
| + return getExpressionPrecedence(parent); |
| +} |
| + |
| + |
| +/** |
| + * Returns the precedence of [node] it is an [Expression], negative otherwise. |
| + */ |
| +int getExpressionPrecedence(AstNode node) { |
| + if (node is Expression) { |
| + return node.precedence; |
| + } |
| + return -1000; |
| +} |
| + |
| + |
| +/** |
| + * Returns the namespace of the given [ImportElement]. |
| + */ |
| +Map<String, Element> getImportNamespace(ImportElement imp) { |
| + NamespaceBuilder builder = new NamespaceBuilder(); |
| + Namespace namespace = builder.createImportNamespaceForDirective(imp); |
| + return namespace.definedNames; |
| +} |
| + |
| + |
| +class CorrectionUtils { |
| + final CompilationUnit unit; |
| + |
| + LibraryElement _library; |
| + String _buffer; |
| + String _endOfLine; |
| + |
| + CorrectionUtils(this.unit) { |
| + CompilationUnitElement element = unit.element; |
| + this._library = element.library; |
| + this._buffer = element.context.getContents(element.source).data; |
| + } |
| + |
| + /** |
| + * Returns 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; |
| + } |
| + |
| + /** |
| + * Skips whitespace characters and single EOL on the right from [index]. |
| + * |
| + * If [index] the end of a statement or method, then in the most cases it is |
| + * a 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 (!isWhitespace(c) || c == 0x0D || c == 0x0A) { |
| + break; |
| + } |
| + index++; |
| + } |
| + // skip single \r |
| + if (index < length && _buffer.codeUnitAt(index) == 0x0D) { |
| + index++; |
| + } |
| + // skip single \n |
| + if (index < length && _buffer.codeUnitAt(index) == 0x0A) { |
| + index++; |
| + } |
| + // done |
| + return index; |
| + } |
| + |
| + /** |
| + * Skips spaces and tabs on the left from [index]. |
| + * |
| + * If [index] is the start or a statement, then in the most cases it is a |
| + * start on its line. |
| + */ |
| + int getLineContentStart(int index) { |
| + while (index > 0) { |
| + int c = _buffer.codeUnitAt(index - 1); |
| + if (!isSpace(c)) { |
| + break; |
| + } |
| + index--; |
| + } |
| + return index; |
| + } |
| + |
| + /** |
| + * Returns a [SourceRange] that covers [range] and extends (if possible) to |
| + * cover whole lines. |
| + */ |
| + SourceRange getLinesRange(SourceRange range) { |
| + // start |
| + int startOffset = range.offset; |
| + int startLineOffset = getLineContentStart(startOffset); |
| + // end |
| + int endOffset = range.end; |
| + int afterEndLineOffset = getLineContentEnd(endOffset); |
| + // range |
| + return rangeStartEnd(startLineOffset, afterEndLineOffset); |
| + } |
| + |
| + /** |
| + * @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 sb = new StringBuffer(); |
| + // return type |
| + DartType returnType = functionType.returnType; |
| + if (returnType != null && !returnType.isDynamic) { |
| + sb.write(getTypeSource2(returnType)); |
| + sb.write(' '); |
| + } |
| + // parameter name |
| + sb.write(name); |
| + // parameters |
| + sb.write('('); |
| + List<ParameterElement> fParameters = functionType.parameters; |
| + for (int i = 0; i < fParameters.length; i++) { |
| + ParameterElement fParameter = fParameters[i]; |
| + if (i != 0) { |
| + sb.write(", "); |
| + } |
| + sb.write(getParameterSource(fParameter.type, fParameter.name)); |
| + } |
| + sb.write(')'); |
| + // done |
| + return sb.toString(); |
| + } |
| + // simple type |
| + return "${getTypeSource2(type)} ${name}"; |
| + } |
| + |
| + /** |
| + * Returns the actual type source of the given [Expression], may be `null` |
| + * if can not be resolved, should be treated as the `dynamic` type. |
| + */ |
| + String getTypeSource(Expression expression) { |
| + if (expression == null) { |
| + return null; |
| + } |
| + DartType type = expression.bestType; |
| + String typeSource = getTypeSource2(type); |
| + if ("dynamic" == typeSource) { |
| + return null; |
| + } |
| + return typeSource; |
| + } |
| + |
| + /** |
| + * Returns the source to reference the given [Type] in this [CompilationUnit]. |
| + */ |
| + String getTypeSource2(DartType type) { |
|
Brian Wilkerson
2014/07/18 13:21:35
I assume we'll rename this.
|
| + StringBuffer sb = new StringBuffer(); |
| + // prepare element |
| + Element element = type.element; |
| + if (element == null) { |
| + String source = type.toString(); |
| + source = source.replaceAll('<dynamic>', ''); |
| + source = source.replaceAll('<dynamic, dynamic>', ''); |
| + return source; |
| + } |
| + // append prefix |
| + { |
| + ImportElement imp = _getImportElement(element); |
| + if (imp != null && imp.prefix != null) { |
| + sb.write(imp.prefix.displayName); |
| + sb.write("."); |
| + } |
| + } |
| + // append simple name |
| + String name = element.displayName; |
| + sb.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) { |
| + sb.write("<"); |
| + for (int i = 0; i < arguments.length; i++) { |
| + DartType argument = arguments[i]; |
| + if (i != 0) { |
| + sb.write(", "); |
| + } |
| + sb.write(getTypeSource2(argument)); |
| + } |
| + sb.write(">"); |
| + } |
| + } |
| + // done |
| + return sb.toString(); |
| + } |
| + |
| + /** |
| + * @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; |
| + } |
| +} |