Use DartEditBuilder to write types and remove dead code

R=scheglov@google.com

Review-Url: https://codereview.chromium.org/2972463003 .
This commit is contained in:
Brian Wilkerson 2017-07-01 12:03:43 -07:00
parent d31ed8690e
commit aadafd1bd5
5 changed files with 75 additions and 190 deletions

View file

@ -221,26 +221,26 @@ class AssistProcessor {
return;
}
_configureTargetLocation(node);
Set<Source> librariesToImport = new Set<Source>();
String typeSource = utils.getTypeSource(type, librariesToImport);
if (typeSource == null) {
// The type source might be null if the type is private.
_coverageMarker();
return;
}
DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
bool validChange = true;
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
Token keyword = declaredIdentifier.keyword;
if (keyword.keyword == Keyword.VAR) {
builder.addSimpleReplacement(range.token(keyword), typeSource);
builder.addReplacement(range.token(keyword), (DartEditBuilder builder) {
validChange = builder.writeType(type);
});
} else {
builder.addSimpleInsertion(
declaredIdentifier.identifier.offset, '$typeSource ');
builder.addInsertion(declaredIdentifier.identifier.offset,
(DartEditBuilder builder) {
validChange = builder.writeType(type);
builder.write(' ');
});
}
builder.importLibraries(librariesToImport);
});
_addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
if (validChange) {
_addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
}
}
Future<Null> _addProposal_addTypeAnnotation_SimpleFormalParameter() async {
@ -269,20 +269,18 @@ class AssistProcessor {
}
// prepare type source
_configureTargetLocation(node);
Set<Source> librariesToImport = new Set<Source>();
String typeSource = utils.getTypeSource(type, librariesToImport);
// type source might be null, if the type is private
if (typeSource == null) {
_coverageMarker();
return;
}
DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
bool validChange = true;
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
builder.addSimpleInsertion(name.offset, '$typeSource ');
builder.importLibraries(librariesToImport);
builder.addInsertion(name.offset, (DartEditBuilder builder) {
validChange = builder.writeType(type);
builder.write(' ');
});
});
_addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
if (validChange) {
_addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
}
}
Future<Null> _addProposal_addTypeAnnotation_VariableDeclaration() async {
@ -325,42 +323,25 @@ class AssistProcessor {
return;
}
_configureTargetLocation(node);
Set<Source> librariesToImport = new Set<Source>();
String typeSource = utils.getTypeSource(type, librariesToImport);
// type source might be null, if the type is private
if (typeSource == null) {
_coverageMarker();
return;
}
DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
if (unitLibraryFile == file) {
// TODO(brianwilkerson) Make ChangeBuilder merge multiple edits to the
// same file so that only the else block is necessary.
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
Token keyword = declarationList.keyword;
if (keyword?.keyword == Keyword.VAR) {
builder.addSimpleReplacement(range.token(keyword), typeSource);
} else {
builder.addSimpleInsertion(variable.offset, '$typeSource ');
}
builder.importLibraries(librariesToImport);
});
} else {
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
Token keyword = declarationList.keyword;
if (keyword?.keyword == Keyword.VAR) {
builder.addSimpleReplacement(range.token(keyword), typeSource);
} else {
builder.addSimpleInsertion(variable.offset, '$typeSource ');
}
});
await changeBuilder.addFileEdit(unitLibraryFile,
(DartFileEditBuilder builder) {
builder.importLibraries(librariesToImport);
});
bool validChange = true;
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
Token keyword = declarationList.keyword;
if (keyword?.keyword == Keyword.VAR) {
builder.addReplacement(range.token(keyword), (DartEditBuilder builder) {
validChange = builder.writeType(type);
});
} else {
builder.addInsertion(variable.offset, (DartEditBuilder builder) {
validChange = builder.writeType(type);
builder.write(' ');
});
}
});
if (validChange) {
_addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
}
_addAssistFromBuilder(changeBuilder, DartAssistKind.ADD_TYPE_ANNOTATION);
}
Future<Null> _addProposal_assignToLocalVariable() async {
@ -1091,8 +1072,6 @@ class AssistProcessor {
String name = (node as SimpleIdentifier).name;
// prepare type
DartType type = parameterElement.type;
Set<Source> librariesToImport = new Set<Source>();
String typeCode = utils.getTypeSource(type, librariesToImport);
DartChangeBuilder changeBuilder = new DartChangeBuilder(driver);
await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
@ -1100,8 +1079,12 @@ class AssistProcessor {
if (type.isDynamic) {
builder.addSimpleReplacement(range.node(parameter), name);
} else {
builder.addSimpleReplacement(
range.node(parameter), '$typeCode $name');
builder.addReplacement(range.node(parameter),
(DartEditBuilder builder) {
builder.writeType(type);
builder.write(' ');
builder.write(name);
});
}
// add field initializer
List<ConstructorInitializer> initializers = constructor.initializers;

View file

@ -709,17 +709,6 @@ class CorrectionUtils {
return _endOfLine;
}
/**
* Returns an [Edit] that changes indentation of the source of the given
* [SourceRange] from [oldIndent] to [newIndent], keeping indentation of lines
* relative to each other.
*/
SourceEdit createIndentEdit(
SourceRange range, String oldIndent, String newIndent) {
String newSource = replaceSourceRangeIndent(range, oldIndent, newIndent);
return new SourceEdit(range.offset, range.length, newSource);
}
/**
* Returns the [AstNode] that encloses the given offset.
*/
@ -742,82 +731,11 @@ class CorrectionUtils {
return conflicts;
}
/**
* 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 getExpressionTypeSource(
Expression expression, Set<Source> librariesToImport) {
if (expression == null) {
return null;
}
DartType type = expression.bestType;
if (type.isDynamic) {
return null;
}
return getTypeSource(type, librariesToImport);
}
/**
* Returns the indentation with the given level.
*/
String getIndent(int level) => repeat(' ', level);
/**
* Returns a [InsertDesc] describing where to insert a new library-related
* directive.
*/
CorrectionUtils_InsertDesc getInsertDescImport() {
// 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 getInsertDescTop();
}
/**
* Returns a [InsertDesc] describing where to insert a new 'part' directive.
*/
CorrectionUtils_InsertDesc getInsertDescPart() {
// 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 getInsertDescTop();
}
/**
* Returns a [InsertDesc] describing where to insert a new directive or a
* top-level declaration at the top of the file.
@ -1031,48 +949,6 @@ class CorrectionUtils {
return getText(node.offset, node.length);
}
/**
* @return the source for the parameter with the given type and name.
*/
String getParameterSource(
DartType type, String name, Set<Source> librariesToImport) {
// no type
if (type == null || type.isDynamic) {
return name;
}
// function type
if (type is FunctionType && type.element.isSynthetic) {
FunctionType functionType = type;
StringBuffer sb = new StringBuffer();
// return type
DartType returnType = functionType.returnType;
if (returnType != null && !returnType.isDynamic) {
String returnTypeSource = getTypeSource(returnType, librariesToImport);
sb.write(returnTypeSource);
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, librariesToImport));
}
sb.write(')');
// done
return sb.toString();
}
// simple type
String typeSource = getTypeSource(type, librariesToImport);
return '$typeSource $name';
}
/**
* Returns the line prefix consisting of spaces and tabs on the left from the
* given offset.

View file

@ -166,7 +166,10 @@ class A<T> {
await assertNoAssistAt('var item', DartAssistKind.ADD_TYPE_ANNOTATION);
}
@failingTest
test_addTypeAnnotation_BAD_privateType_list() async {
// This is now failing because we're suggesting "List" rather than nothing.
// Is it really better to produce nothing?
addSource(
'/my_lib.dart',
'''

View file

@ -486,7 +486,7 @@ class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder {
String typeSource = _getTypeSource(
type, finder.enclosingClass, finder.enclosingExecutable,
methodBeingCopied: methodBeingCopied);
if (typeSource != 'dynamic') {
if (typeSource.isNotEmpty && typeSource != 'dynamic') {
if (groupName != null) {
addLinkedEdit(groupName, (LinkedEditBuilder builder) {
write(typeSource);
@ -957,6 +957,17 @@ class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder {
parameterParent == enclosingClass ||
parameterParent == methodBeingCopied;
}
Element element = type.element;
if (element == null) {
return true;
}
LibraryElement definingLibrary = element.library;
LibraryElement importingLibrary = dartFileEditBuilder.unit.element.library;
if (definingLibrary != null && definingLibrary != importingLibrary) {
if (element.isPrivate) {
return false;
}
}
return true;
}
}
@ -1015,8 +1026,19 @@ class DartFileEditBuilderImpl extends FileEditBuilderImpl
@override
void finalize() {
_addLibraryImports(
changeBuilder.sourceChange, unit.element.library, librariesToImport);
CompilationUnitElement unitElement = unit.element;
LibraryElement libraryElement = unitElement.library;
CompilationUnitElement definingUnitElement =
libraryElement.definingCompilationUnit;
if (definingUnitElement == unitElement) {
_addLibraryImports(libraryElement, librariesToImport);
} else {
(changeBuilder as DartChangeBuilder).addFileEdit(
definingUnitElement.source.fullName, (DartFileEditBuilder builder) {
(builder as DartFileEditBuilderImpl)
._addLibraryImports(libraryElement, librariesToImport);
});
}
}
@override
@ -1051,11 +1073,10 @@ class DartFileEditBuilderImpl extends FileEditBuilderImpl
}
/**
* Adds edits to the given [change] that ensure that all the [libraries] are
* imported into the given [targetLibrary].
* Adds edits ensure that all the [libraries] are imported into the given
* [targetLibrary].
*/
void _addLibraryImports(SourceChange change, LibraryElement targetLibrary,
Set<Source> libraries) {
void _addLibraryImports(LibraryElement targetLibrary, Set<Source> libraries) {
// Prepare information about existing imports.
LibraryDirective libraryDirective;
List<ImportDirective> importDirectives = <ImportDirective>[];

View file

@ -226,6 +226,8 @@ abstract class DartEditBuilder implements EditBuilder {
* If a [methodBeingCopied] is provided, then type parameters defined by that
* method are assumed to be part of what is being written and hence valid
* types.
*
* Return `true` if some text was written.
*/
bool writeType(DartType type,
{bool addSupertypeProposals: false,