Issue 26335. Insert an empty line if the class body is a single line.

R=brianwilkerson@google.com
BUG= https://github.com/dart-lang/sdk/issues/26335

Review URL: https://codereview.chromium.org/2256463002 .
This commit is contained in:
Konstantin Shcheglov 2016-08-16 15:13:22 -07:00
parent 462204e557
commit 010578b88a
2 changed files with 119 additions and 106 deletions

View file

@ -697,14 +697,12 @@ class FixProcessor {
}
}
// prepare location for a new constructor
_ConstructorLocation targetLocation =
_ClassMemberLocation targetLocation =
_prepareNewConstructorLocation(classDeclaration);
// build constructor source
SourceBuilder sb = new SourceBuilder(file, targetLocation.offset);
{
String indent = ' ';
sb.append(targetLocation.prefix);
sb.append(indent);
sb.append(classDeclaration.name.name);
sb.append('(');
sb.append(fieldNames.map((name) => 'this.$name').join(', '));
@ -743,19 +741,17 @@ class FixProcessor {
if (targetTypeNode is! ClassDeclaration) {
return;
}
_ConstructorLocation targetLocation =
_ClassMemberLocation targetLocation =
_prepareNewConstructorLocation(targetTypeNode);
String targetFile = targetElement.source.fullName;
// build method source
SourceBuilder sb = new SourceBuilder(targetFile, targetLocation.offset);
{
String indent = ' ';
sb.append(targetLocation.prefix);
sb.append(indent);
sb.append(targetElement.name);
_addFix_undefinedMethod_create_parameters(
sb, instanceCreation.argumentList);
sb.append(') {$eol$indent}');
sb.append(');');
sb.append(targetLocation.suffix);
}
// insert source
@ -801,15 +797,13 @@ class FixProcessor {
if (targetTypeNode is! ClassDeclaration) {
return;
}
_ConstructorLocation targetLocation =
_ClassMemberLocation targetLocation =
_prepareNewConstructorLocation(targetTypeNode);
String targetFile = targetElement.source.fullName;
// build method source
SourceBuilder sb = new SourceBuilder(targetFile, targetLocation.offset);
{
String indent = ' ';
sb.append(targetLocation.prefix);
sb.append(indent);
sb.append(targetElement.name);
sb.append('.');
// append name
@ -820,7 +814,7 @@ class FixProcessor {
}
_addFix_undefinedMethod_create_parameters(
sb, instanceCreation.argumentList);
sb.append(') {$eol$indent}');
sb.append(');');
sb.append(targetLocation.suffix);
}
// insert source
@ -941,13 +935,11 @@ class FixProcessor {
argumentsBuffer.append(parameterName);
}
// add proposal
_ConstructorLocation targetLocation =
_ClassMemberLocation targetLocation =
_prepareNewConstructorLocation(targetClassNode);
SourceBuilder sb = new SourceBuilder(file, targetLocation.offset);
{
String indent = utils.getIndent(1);
sb.append(targetLocation.prefix);
sb.append(indent);
sb.append(targetClassName);
if (!constructorName.isEmpty) {
sb.startPosition('NAME');
@ -1025,7 +1017,8 @@ class FixProcessor {
}
ClassDeclaration targetClassNode = targetTypeNode;
// prepare location
_FieldLocation targetLocation = _prepareNewFieldLocation(targetClassNode);
_ClassMemberLocation targetLocation =
_prepareNewFieldLocation(targetClassNode);
// build method source
String targetFile = targetClassElement.source.fullName;
SourceBuilder sb = new SourceBuilder(targetFile, targetLocation.offset);
@ -1157,7 +1150,8 @@ class FixProcessor {
}
ClassDeclaration targetClassNode = targetTypeNode;
// prepare location
_FieldLocation targetLocation = _prepareNewGetterLocation(targetClassNode);
_ClassMemberLocation targetLocation =
_prepareNewGetterLocation(targetClassNode);
// build method source
String targetFile = targetClassElement.source.fullName;
SourceBuilder sb = new SourceBuilder(targetFile, targetLocation.offset);
@ -1284,7 +1278,7 @@ class FixProcessor {
// EOL management
bool isFirst = true;
void addEolIfNotFirst() {
if (!isFirst || !targetClass.members.isEmpty) {
if (!isFirst || _isClassWithEmptyBody(targetClass)) {
sb.append(eol);
}
isFirst = false;
@ -2739,74 +2733,62 @@ class FixProcessor {
return node is SimpleIdentifier && node.name == 'await';
}
_ConstructorLocation _prepareNewConstructorLocation(
/**
* Return `true` if the given [classDeclaration] has open '{' and close '}'
* at the same line, e.g. `class X {}`.
*/
bool _isClassWithEmptyBody(ClassDeclaration classDeclaration) {
return utils.getLineThis(classDeclaration.leftBracket.offset) ==
utils.getLineThis(classDeclaration.rightBracket.offset);
}
_ClassMemberLocation _prepareNewClassMemberLocation(
ClassDeclaration classDeclaration,
bool shouldSkip(ClassMember existingMember)) {
String indent = utils.getIndent(1);
// Find the last target member.
ClassMember targetMember = null;
List<ClassMember> members = classDeclaration.members;
for (ClassMember member in members) {
if (shouldSkip(member)) {
targetMember = member;
} else {
break;
}
}
// After the last target member.
if (targetMember != null) {
return new _ClassMemberLocation(eol + eol + indent, targetMember.end, '');
}
// At the beginning of the class.
String suffix = members.isNotEmpty ||
_isClassWithEmptyBody(classDeclaration) ? eol : '';
return new _ClassMemberLocation(
eol + indent, classDeclaration.leftBracket.end, suffix);
}
_ClassMemberLocation _prepareNewConstructorLocation(
ClassDeclaration classDeclaration) {
List<ClassMember> members = classDeclaration.members;
// find the last field/constructor
ClassMember lastFieldOrConstructor = null;
for (ClassMember member in members) {
if (member is FieldDeclaration || member is ConstructorDeclaration) {
lastFieldOrConstructor = member;
} else {
break;
}
}
// after the last field/constructor
if (lastFieldOrConstructor != null) {
return new _ConstructorLocation(
eol + eol, lastFieldOrConstructor.end, '');
}
// at the beginning of the class
String suffix = members.isEmpty ? '' : eol;
return new _ConstructorLocation(
eol, classDeclaration.leftBracket.end, suffix);
return _prepareNewClassMemberLocation(
classDeclaration,
(member) =>
member is FieldDeclaration || member is ConstructorDeclaration);
}
_FieldLocation _prepareNewFieldLocation(ClassDeclaration classDeclaration) {
String indent = utils.getIndent(1);
// find the last field
ClassMember lastFieldOrConstructor = null;
List<ClassMember> members = classDeclaration.members;
for (ClassMember member in members) {
if (member is FieldDeclaration) {
lastFieldOrConstructor = member;
} else {
break;
}
}
// after the last field
if (lastFieldOrConstructor != null) {
return new _FieldLocation(
eol + eol + indent, lastFieldOrConstructor.end, '');
}
// at the beginning of the class
String suffix = members.isEmpty ? '' : eol;
return new _FieldLocation(
eol + indent, classDeclaration.leftBracket.end, suffix);
_ClassMemberLocation _prepareNewFieldLocation(
ClassDeclaration classDeclaration) {
return _prepareNewClassMemberLocation(
classDeclaration, (member) => member is FieldDeclaration);
}
_FieldLocation _prepareNewGetterLocation(ClassDeclaration classDeclaration) {
String indent = utils.getIndent(1);
// find an existing target member
ClassMember prevMember = null;
List<ClassMember> members = classDeclaration.members;
for (ClassMember member in members) {
if (member is FieldDeclaration ||
member is ConstructorDeclaration ||
member is MethodDeclaration && member.isGetter) {
prevMember = member;
} else {
break;
}
}
// after the last field/getter
if (prevMember != null) {
return new _FieldLocation(eol + eol + indent, prevMember.end, '');
}
// at the beginning of the class
String suffix = members.isEmpty ? '' : eol;
return new _FieldLocation(
eol + indent, classDeclaration.leftBracket.end, suffix);
_ClassMemberLocation _prepareNewGetterLocation(
ClassDeclaration classDeclaration) {
return _prepareNewClassMemberLocation(
classDeclaration,
(member) =>
member is FieldDeclaration ||
member is ConstructorDeclaration ||
member is MethodDeclaration && member.isGetter);
}
/**
@ -2927,6 +2909,17 @@ class LintNames {
static const String annotate_overrides = 'annotate_overrides';
}
/**
* Describes the location for a newly created [ClassMember].
*/
class _ClassMemberLocation {
final String prefix;
final int offset;
final String suffix;
_ClassMemberLocation(this.prefix, this.offset, this.suffix);
}
/**
* Helper for finding [Element] with name closest to the given.
*/
@ -2955,25 +2948,3 @@ class _ClosestElementFinder {
}
}
}
/**
* Describes the location for a newly created [ConstructorDeclaration].
*/
class _ConstructorLocation {
final String prefix;
final int offset;
final String suffix;
_ConstructorLocation(this.prefix, this.offset, this.suffix);
}
/**
* Describes the location for a newly created [FieldDeclaration].
*/
class _FieldLocation {
final String prefix;
final int offset;
final String suffix;
_FieldLocation(this.prefix, this.offset, this.suffix);
}

View file

@ -1011,8 +1011,7 @@ main() {
class A {
int field;
A(int i, double d) {
}
A(int i, double d);
method() {}
}
@ -1035,8 +1034,7 @@ main() {
DartFixKind.CREATE_CONSTRUCTOR,
'''
class A {
A.named(int i, double d) {
}
A.named(int i, double d);
method() {}
}
@ -1047,6 +1045,26 @@ main() {
_assertLinkedGroup(change.linkedEditGroups[0], ['named(int ', 'named(1']);
}
test_createConstructor_named_emptyClassBody() async {
resolveTestUnit('''
class A {}
main() {
new A.named(1);
}
''');
await assertHasFix(
DartFixKind.CREATE_CONSTRUCTOR,
'''
class A {
A.named(int i);
}
main() {
new A.named(1);
}
''');
_assertLinkedGroup(change.linkedEditGroups[0], ['named(int ', 'named(1']);
}
test_createConstructorForFinalFields_inTopLevelMethod() async {
resolveTestUnit('''
main() {
@ -2569,6 +2587,30 @@ class B extends A {
}
}
test_createMissingOverrides_method_emptyClassBody() async {
resolveTestUnit('''
abstract class A {
void foo();
}
class B extends A {}
''');
await assertHasFix(
DartFixKind.CREATE_MISSING_OVERRIDES,
'''
abstract class A {
void foo();
}
class B extends A {
@override
void foo() {
// TODO: implement foo
}
}
''');
}
test_createMissingOverrides_operator() async {
resolveTestUnit('''
abstract class A {