Remove unintentional dependency on analysis_server

R=scheglov@google.com

Review-Url: https://codereview.chromium.org/2875323002 .
This commit is contained in:
Brian Wilkerson 2017-05-12 10:07:36 -07:00
parent 25e8941cc7
commit bef53e72e4
18 changed files with 556 additions and 145 deletions

View file

@ -46,6 +46,7 @@ import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer_plugin/src/utilities/string_utilities.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
import 'package:path/path.dart';

View file

@ -2,12 +2,11 @@
// 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.name_suggestion;
import 'package:analysis_server/src/services/correction/strings.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer_plugin/src/utilities/string_utilities.dart';
List<String> _KNOWN_METHOD_NAME_PREFIXES = ['get', 'is', 'to'];

View file

@ -2,10 +2,10 @@
// 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.strings;
import 'dart:math';
import 'package:analyzer_plugin/src/utilities/string_utilities.dart';
/**
* "$"
*/
@ -158,46 +158,6 @@ int findCommonSuffix(String a, String b) {
return n;
}
/**
* Returns a list of words for the given camel case string.
*
* 'getCamelWords' => ['get', 'Camel', 'Words']
* 'getHTMLText' => ['get', 'HTML', 'Text']
*/
List<String> getCamelWords(String str) {
if (str == null || str.isEmpty) {
return <String>[];
}
List<String> parts = <String>[];
bool wasLowerCase = false;
bool wasUpperCase = false;
int wordStart = 0;
for (int i = 0; i < str.length; i++) {
int c = str.codeUnitAt(i);
var newLowerCase = isLowerCase(c);
var newUpperCase = isUpperCase(c);
// myWord
// | ^
if (wasLowerCase && newUpperCase) {
parts.add(str.substring(wordStart, i));
wordStart = i;
}
// myHTMLText
// | ^
if (wasUpperCase &&
newUpperCase &&
i + 1 < str.length &&
isLowerCase(str.codeUnitAt(i + 1))) {
parts.add(str.substring(wordStart, i));
wordStart = i;
}
wasLowerCase = newLowerCase;
wasUpperCase = newUpperCase;
}
parts.add(str.substring(wordStart));
return parts;
}
/**
* Checks if [str] is `null`, empty or is whitespace.
*/
@ -215,10 +175,6 @@ bool isDigit(int c) {
return c >= 0x30 && c <= 0x39;
}
bool isEmpty(String str) {
return str == null || str.isEmpty;
}
bool isEOL(int c) {
return c == 0x0D || c == 0x0A;
}
@ -231,16 +187,8 @@ bool isLetterOrDigit(int c) {
return isLetter(c) || isDigit(c);
}
bool isLowerCase(int c) {
return c >= 0x61 && c <= 0x7A;
}
bool isSpace(int c) => c == 0x20 || c == 0x09;
bool isUpperCase(int c) {
return c >= 0x41 && c <= 0x5A;
}
bool isWhitespace(int c) {
return isSpace(c) || isEOL(c);
}
@ -262,16 +210,6 @@ String removeEnd(String str, String remove) {
return str;
}
String removeStart(String str, String remove) {
if (isEmpty(str) || isEmpty(remove)) {
return str;
}
if (str.startsWith(remove)) {
return str.substring(remove.length);
}
return str;
}
String repeat(String s, int n) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < n; i++) {

View file

@ -2,8 +2,6 @@
// 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.util;
import 'dart:math';
import 'package:analysis_server/protocol/protocol_generated.dart'
@ -22,6 +20,7 @@ import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/src/utilities/string_utilities.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
import 'package:path/path.dart';

View file

@ -2,10 +2,9 @@
// 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.refactoring.naming_conventions;
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/correction/strings.dart';
import 'package:analyzer_plugin/src/utilities/string_utilities.dart';
import 'package:front_end/src/scanner/token.dart' show Keyword;
/**

View file

@ -4,7 +4,7 @@
import 'dart:io';
import 'package:analysis_server/src/services/correction/strings.dart';
import 'package:analyzer_plugin/src/utilities/string_utilities.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';

View file

@ -2,8 +2,6 @@
// 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 test.services.correction.strings;
import 'package:analysis_server/src/services/correction/strings.dart';
import 'package:test/test.dart' hide isEmpty;
import 'package:test_reflective_loader/test_reflective_loader.dart';
@ -75,13 +73,6 @@ class StringsTest {
expect(findCommonSuffix('123', 'xyz123'), 3);
}
void test_getCamelWords() {
expect(getCamelWords(null), []);
expect(getCamelWords(''), []);
expect(getCamelWords('getCamelWords'), ['get', 'Camel', 'Words']);
expect(getCamelWords('getHTMLText'), ['get', 'HTML', 'Text']);
}
void test_isBlank() {
expect(isBlank(null), isTrue);
expect(isBlank(''), isTrue);
@ -99,13 +90,6 @@ class StringsTest {
expect(isDigit('A'.codeUnitAt(0)), isFalse);
}
void test_isEmpty() {
expect(isEmpty(null), isTrue);
expect(isEmpty(''), isTrue);
expect(isEmpty('X'), isFalse);
expect(isEmpty(' '), isFalse);
}
void test_isLetter() {
for (int c in 'abcdefghijklmnopqrstuvwxyz'.codeUnits) {
expect(isLetter(c), isTrue);
@ -131,17 +115,6 @@ class StringsTest {
expect(isLetterOrDigit('.'.codeUnitAt(0)), isFalse);
}
void test_isLowerCase() {
for (int c in 'abcdefghijklmnopqrstuvwxyz'.codeUnits) {
expect(isLowerCase(c), isTrue);
}
for (int c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.codeUnits) {
expect(isLowerCase(c), isFalse);
}
expect(isLowerCase(' '.codeUnitAt(0)), isFalse);
expect(isLowerCase('0'.codeUnitAt(0)), isFalse);
}
void test_isSpace() {
expect(isSpace(' '.codeUnitAt(0)), isTrue);
expect(isSpace('\t'.codeUnitAt(0)), isTrue);
@ -151,17 +124,6 @@ class StringsTest {
expect(isSpace('A'.codeUnitAt(0)), isFalse);
}
void test_isUpperCase() {
for (int c in 'abcdefghijklmnopqrstuvwxyz'.codeUnits) {
expect(isUpperCase(c), isFalse);
}
for (int c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.codeUnits) {
expect(isUpperCase(c), isTrue);
}
expect(isUpperCase(' '.codeUnitAt(0)), isFalse);
expect(isUpperCase('0'.codeUnitAt(0)), isFalse);
}
void test_isWhitespace() {
expect(isWhitespace(' '.codeUnitAt(0)), isTrue);
expect(isWhitespace('\t'.codeUnitAt(0)), isTrue);
@ -186,13 +148,6 @@ class StringsTest {
expect(removeEnd('www.domain.com', '.com'), 'www.domain');
}
void test_removeStart() {
expect(removeStart(null, 'x'), null);
expect(removeStart('abc', null), 'abc');
expect(removeStart('abcTest', 'abc'), 'Test');
expect(removeStart('my abcTest', 'abc'), 'my abcTest');
}
void test_repeat() {
expect(repeat('x', 0), '');
expect(repeat('x', 5), 'xxxxx');

View file

@ -3,9 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/services/correction/strings.dart';
import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/src/utilities/string_utilities.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

View file

@ -292,6 +292,14 @@ class LineInfo {
}
return lineStarts[lineNumber];
}
/**
* Return the offset of the first character on the line following the line
* containing the given [offset].
*/
int getOffsetOfLineAfter(int offset) {
return getOffsetOfLine(getLocation(offset).lineNumber + 1);
}
}
/**

View file

@ -4,8 +4,8 @@
import 'dart:async';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
/**

View file

@ -4,10 +4,6 @@
import 'dart:async';
import 'package:analysis_server/protocol/protocol_generated.dart'
hide Element, ElementKind;
import 'package:analysis_server/src/services/correction/name_suggestion.dart';
import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
@ -17,10 +13,15 @@ import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart'
hide Element, ElementKind;
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/src/utilities/string_utilities.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
import 'package:charcode/ascii.dart';
import 'package:path/path.dart' as path;
/**
* A [ChangeBuilder] used to build changes in Dart files.
@ -49,6 +50,8 @@ class DartChangeBuilderImpl extends ChangeBuilderImpl
* An [EditBuilder] used to build edits in Dart files.
*/
class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder {
List<String> _KNOWN_METHOD_NAME_PREFIXES = ['get', 'is', 'to'];
/**
* Initialize a newly created builder to build a source edit.
*/
@ -543,6 +546,45 @@ class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder {
}
}
/**
* Adds [toAdd] items which are not excluded.
*/
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;
}
}
}
}
/**
* Adds to [result] either [c] or the first ASCII character after it.
*/
void _addSingleCharacterName(
Set<String> excluded, Set<String> result, int c) {
while (c < $z) {
String name = new String.fromCharCode(c);
// may be done
if (!excluded.contains(name)) {
result.add(name);
break;
}
// next character
c = c + 1;
}
}
void _addSuperTypeProposals(
LinkedEditBuilder builder, DartType type, Set<DartType> alreadyAdded) {
if (type != null &&
@ -557,21 +599,124 @@ class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder {
}
}
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 PropertyAccess) {
PropertyAccess node = expression;
return node.propertyName.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 prefix = _KNOWN_METHOD_NAME_PREFIXES[i];
if (name.startsWith(prefix)) {
if (name == prefix) {
return null;
} else if (isUpperCase(name.codeUnitAt(prefix.length))) {
return name.substring(prefix.length);
}
}
}
}
// done
return name;
}
String _getBaseNameFromLocationInParent(Expression expression) {
// value in named expression
if (expression.parent is NamedExpression) {
NamedExpression namedExpression = expression.parent as NamedExpression;
if (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;
}
/**
* Returns all variants of names by removing leading words one by one.
*/
List<String> _getCamelWordCombinations(String name) {
List<String> result = [];
List<String> parts = getCamelWords(name);
for (int i = 0; i < parts.length; i++) {
String s1 = parts[i].toLowerCase();
String s2 = parts.skip(i + 1).join();
String suggestion = '$s1$s2';
result.add(suggestion);
}
return result;
}
/**
* Return the import element used to import the given [element] into the given
* [library], or `null` if the element was not imported, such as when the
* element is declared in the same library.
*/
ImportElement _getImportElement(Element element, LibraryElement library) {
for (ImportElement imp in library.imports) {
Map<String, Element> definedNames = getImportNamespace(imp);
for (ImportElement importElement in library.imports) {
Map<String, Element> definedNames = _getImportNamespace(importElement);
if (definedNames.containsValue(element)) {
return imp;
return importElement;
}
}
return null;
}
/**
* Return the namespace added by the given import [element].
*/
Map<String, Element> _getImportNamespace(ImportElement element) {
NamespaceBuilder builder = new NamespaceBuilder();
Namespace namespace = builder.createImportNamespaceForDirective(element);
return namespace.definedNames;
}
/**
* Return a list containing the suggested names for a parameter with the given
* [type] whose value in one location is computed by the given [expression].
@ -582,7 +727,7 @@ class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder {
List<String> _getParameterNameSuggestions(
Set<String> usedNames, DartType type, Expression expression, int index) {
List<String> suggestions =
getVariableNameSuggestionsForExpression(type, expression, usedNames);
_getVariableNameSuggestionsForExpression(type, expression, usedNames);
if (suggestions.length != 0) {
return suggestions;
}
@ -737,6 +882,45 @@ class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder {
return sb.toString();
}
/**
* Returns possible names for a variable with the given expected type and
* expression assigned.
*/
List<String> _getVariableNameSuggestionsForExpression(DartType expectedType,
Expression assignedExpression, Set<String> excluded) {
Set<String> res = new Set();
// use expression
if (assignedExpression != null) {
String nameFromExpression =
_getBaseNameFromExpression(assignedExpression);
if (nameFromExpression != null) {
nameFromExpression = removeStart(nameFromExpression, '_');
_addAll(excluded, res, _getCamelWordCombinations(nameFromExpression));
}
String nameFromParent =
_getBaseNameFromLocationInParent(assignedExpression);
if (nameFromParent != null) {
_addAll(excluded, res, _getCamelWordCombinations(nameFromParent));
}
}
// use type
if (expectedType != null && !expectedType.isDynamic) {
String typeName = expectedType.name;
if ('int' == typeName) {
_addSingleCharacterName(excluded, res, $i);
} else if ('double' == typeName) {
_addSingleCharacterName(excluded, res, $d);
} else if ('String' == typeName) {
_addSingleCharacterName(excluded, res, $s);
} else {
_addAll(excluded, res, _getCamelWordCombinations(typeName));
}
res.remove(typeName);
}
// done
return new List.from(res);
}
/**
* Checks if [type] is visible in either the [enclosingExecutable] or
* [enclosingClass].
@ -806,25 +990,10 @@ class DartFileEditBuilderImpl extends FileEditBuilderImpl
@override
void finalize() {
addLibraryImports(
_addLibraryImports(
changeBuilder.sourceChange, unit.element.library, librariesToImport);
}
// /**
// * Return the content of the file being edited.
// */
// String getContent() {
// if (_content == null) {
// CompilationUnitElement unitElement = unit.element;
// AnalysisContext context = unitElement.context;
// if (context == null) {
// throw new CancelCorrectionException();
// }
// _content = context.getContents(unitElement.source).data;
// }
// return _content;
// }
@override
void importLibraries(Iterable<Source> libraries) {
librariesToImport.addAll(libraries);
@ -852,6 +1021,203 @@ class DartFileEditBuilderImpl extends FileEditBuilderImpl
});
}
/**
* Adds edits to the given [change] that ensure that all the [libraries] are
* imported into the given [targetLibrary].
*/
void _addLibraryImports(SourceChange change, LibraryElement targetLibrary,
Set<Source> libraries) {
// Prepare information about existing imports.
LibraryDirective libraryDirective;
List<ImportDirective> importDirectives = <ImportDirective>[];
for (Directive directive in unit.directives) {
if (directive is LibraryDirective) {
libraryDirective = directive;
} else if (directive is ImportDirective) {
importDirectives.add(directive);
}
}
// Prepare all URIs to import.
List<String> uriList = libraries
.map((library) => _getLibrarySourceUri(targetLibrary, library))
.toList();
uriList.sort((a, b) => a.compareTo(b));
// Insert imports: between existing imports.
if (importDirectives.isNotEmpty) {
bool isFirstPackage = true;
for (String importUri in uriList) {
bool inserted = false;
bool isPackage = importUri.startsWith('package:');
bool isAfterDart = false;
for (ImportDirective existingImport in importDirectives) {
if (existingImport.uriContent.startsWith('dart:')) {
isAfterDart = true;
}
if (existingImport.uriContent.startsWith('package:')) {
isFirstPackage = false;
}
if (importUri.compareTo(existingImport.uriContent) < 0) {
addInsertion(existingImport.offset, (EditBuilder builder) {
builder.write("import '");
builder.write(importUri);
builder.writeln("';");
});
inserted = true;
break;
}
}
if (!inserted) {
addInsertion(importDirectives.last.end, (EditBuilder builder) {
if (isPackage && isFirstPackage && isAfterDart) {
builder.writeln();
}
builder.writeln();
builder.write("import '");
builder.write(importUri);
builder.write("';");
});
}
if (isPackage) {
isFirstPackage = false;
}
}
return;
}
// Insert imports: after the library directive.
if (libraryDirective != null) {
for (int i = 0; i < uriList.length; i++) {
String importUri = uriList[i];
addInsertion(libraryDirective.end, (EditBuilder builder) {
if (i == 0) {
builder.writeln();
}
builder.writeln();
builder.write("import '");
builder.write(importUri);
builder.writeln("';");
});
}
return;
}
// If still at the beginning of the file, skip shebang and line comments.
_InsertionDescription desc = _getInsertDescTop();
int offset = desc.offset;
for (int i = 0; i < uriList.length; i++) {
String importUri = uriList[i];
addInsertion(offset, (EditBuilder builder) {
if (i == 0 && desc.insertEmptyLineBefore) {
builder.writeln();
}
builder.write("import '");
builder.write(importUri);
builder.writeln("';");
if (i == uriList.length - 1 && desc.insertEmptyLineAfter) {
builder.writeln();
}
});
}
}
/**
* Returns a [InsertDesc] describing where to insert a new directive or a
* top-level declaration at the top of the file.
*/
_InsertionDescription _getInsertDescTop() {
// skip leading line comments
int offset = 0;
bool insertEmptyLineBefore = false;
bool insertEmptyLineAfter = false;
String source = unit.element.context.getContents(unit.element.source).data;
var lineInfo = unit.lineInfo;
// skip hash-bang
if (offset < source.length - 2) {
String linePrefix = _getText(source, offset, 2);
if (linePrefix == "#!") {
insertEmptyLineBefore = true;
offset = lineInfo.getOffsetOfLineAfter(offset);
// skip empty lines to first line comment
int emptyOffset = offset;
while (emptyOffset < source.length - 2) {
int nextLineOffset = lineInfo.getOffsetOfLineAfter(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 = _getText(source, offset, 2);
if (linePrefix == "//") {
insertEmptyLineBefore = true;
offset = lineInfo.getOffsetOfLineAfter(offset);
} else {
break;
}
}
// determine if empty line is required after
int currentLine = lineInfo.getLocation(offset).lineNumber;
if (currentLine < lineInfo.lineCount) {
int nextLineOffset = lineInfo.getOffsetOfLine(currentLine + 1);
String insertLine = source.substring(offset, nextLineOffset);
if (!insertLine.trim().isEmpty) {
insertEmptyLineAfter = true;
}
}
return new _InsertionDescription(
offset, insertEmptyLineBefore, insertEmptyLineAfter);
}
// /**
// * Return the content of the file being edited.
// */
// String getContent() {
// if (_content == null) {
// CompilationUnitElement unitElement = unit.element;
// AnalysisContext context = unitElement.context;
// if (context == null) {
// throw new CancelCorrectionException();
// }
// _content = context.getContents(unitElement.source).data;
// }
// return _content;
// }
/**
* Computes the best URI to import [what] into [from].
*/
String _getLibrarySourceUri(LibraryElement from, Source what) {
String whatPath = what.fullName;
// check if an absolute URI (such as 'dart:' or 'package:')
Uri whatUri = what.uri;
String whatUriScheme = whatUri.scheme;
if (whatUriScheme != '' && whatUriScheme != 'file') {
return whatUri.toString();
}
// compute a relative URI
String fromFolder = path.dirname(from.source.fullName);
String relativeFile = path.relative(whatPath, from: fromFolder);
return path.split(relativeFile).join('/');
}
/**
* Returns the text of the given range in the unit.
*/
String _getText(String content, int offset, int length) {
return content.substring(offset, offset + length);
}
// /**
// * Returns the text of the given [AstNode] in the unit.
// */
@ -940,3 +1306,11 @@ class _EnclosingElementFinder {
}
}
}
class _InsertionDescription {
final int offset;
final bool insertEmptyLineBefore;
final bool insertEmptyLineAfter;
_InsertionDescription(
this.offset, this.insertEmptyLineBefore, this.insertEmptyLineAfter);
}

View file

@ -0,0 +1,76 @@
// Copyright (c) 2017, 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.
import 'package:charcode/ascii.dart';
/**
* Returns a list of the words from which the given camel case [string] is
* composed.
*
* 'getCamelWords' => ['get', 'Camel', 'Words']
* 'getHTMLText' => ['get', 'HTML', 'Text']
*/
List<String> getCamelWords(String string) {
if (string == null || string.isEmpty) {
return const <String>[];
}
List<String> parts = <String>[];
bool wasLowerCase = false;
bool wasUpperCase = false;
int wordStart = 0;
for (int i = 0; i < string.length; i++) {
int c = string.codeUnitAt(i);
var newLowerCase = isLowerCase(c);
var newUpperCase = isUpperCase(c);
// myWord
// | ^
if (wasLowerCase && newUpperCase) {
parts.add(string.substring(wordStart, i));
wordStart = i;
}
// myHTMLText
// | ^
if (wasUpperCase &&
newUpperCase &&
i + 1 < string.length &&
isLowerCase(string.codeUnitAt(i + 1))) {
parts.add(string.substring(wordStart, i));
wordStart = i;
}
wasLowerCase = newLowerCase;
wasUpperCase = newUpperCase;
}
parts.add(string.substring(wordStart));
return parts;
}
/**
* Return `true` if the given [string] is either `null` or empty.
*/
bool isEmpty(String string) => string == null || string.isEmpty;
/**
* Return `true` if the given [character] is a lowercase ASCII character.
*/
bool isLowerCase(int character) => character >= $a && character <= $z;
/**
* Return `true` if the given [character] is an uppercase ASCII character.
*/
bool isUpperCase(int character) => character >= $A && character <= $Z;
/**
* If the given [string] starts with the text to [remove], then return the
* portion of the string after the text to remove. Otherwise, return the
* original string unmodified.
*/
String removeStart(String string, String remove) {
if (isEmpty(string) || isEmpty(remove)) {
return string;
}
if (string.startsWith(remove)) {
return string.substring(remove.length);
}
return string;
}

View file

@ -4,8 +4,8 @@
import 'dart:async';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart';
import 'package:meta/meta.dart';

View file

@ -8,6 +8,7 @@ environment:
dependencies:
analyzer: ^0.30.0
charcode: ^1.1.0
html: any
path: any
pub_semver: any

View file

@ -2,8 +2,8 @@
// 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.
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:test/test.dart';

View file

@ -4,7 +4,6 @@
import 'dart:async';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/element/element.dart';
@ -15,6 +14,7 @@ import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/testing/test_type_provider.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart';
import 'package:analyzer_plugin/src/utilities/change_builder/change_builder_dart.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';

View file

@ -0,0 +1,59 @@
// Copyright (c) 2017, 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.
import 'package:analyzer_plugin/src/utilities/string_utilities.dart';
import 'package:test/test.dart' hide isEmpty;
import 'package:test_reflective_loader/test_reflective_loader.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(StringUtilitiesTest);
});
}
@reflectiveTest
class StringUtilitiesTest {
void test_getCamelWords() {
expect(getCamelWords(null), []);
expect(getCamelWords(''), []);
expect(getCamelWords('getCamelWords'), ['get', 'Camel', 'Words']);
expect(getCamelWords('getHTMLText'), ['get', 'HTML', 'Text']);
}
void test_isEmpty() {
expect(isEmpty(null), isTrue);
expect(isEmpty(''), isTrue);
expect(isEmpty('X'), isFalse);
expect(isEmpty(' '), isFalse);
}
void test_isLowerCase() {
for (int c in 'abcdefghijklmnopqrstuvwxyz'.codeUnits) {
expect(isLowerCase(c), isTrue);
}
for (int c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.codeUnits) {
expect(isLowerCase(c), isFalse);
}
expect(isLowerCase(' '.codeUnitAt(0)), isFalse);
expect(isLowerCase('0'.codeUnitAt(0)), isFalse);
}
void test_isUpperCase() {
for (int c in 'abcdefghijklmnopqrstuvwxyz'.codeUnits) {
expect(isUpperCase(c), isFalse);
}
for (int c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.codeUnits) {
expect(isUpperCase(c), isTrue);
}
expect(isUpperCase(' '.codeUnitAt(0)), isFalse);
expect(isUpperCase('0'.codeUnitAt(0)), isFalse);
}
void test_removeStart() {
expect(removeStart(null, 'x'), null);
expect(removeStart('abc', null), 'abc');
expect(removeStart('abcTest', 'abc'), 'Test');
expect(removeStart('my abcTest', 'abc'), 'my abcTest');
}
}

View file

@ -5,9 +5,11 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'change_builder/test_all.dart' as change_builder;
import 'string_utilities_test.dart' as string_utilities;
main() {
defineReflectiveSuite(() {
change_builder.main();
string_utilities.main();
}, name: 'utilities');
}