[Analyzer] Keep comments when organizing imports

This change adjusts the organize imports logic, to keep any comments
written in the line above an import statement attached when
organizing the imports, while being smart about what comments to keep.

Closes https://github.com/dart-lang/sdk/issues/42515
Change-Id: Ibcca4f24411ac16bcdb17f66fb6d2b9c45f7d367
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/157743
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Jonas Hungershausen 2020-08-11 15:03:59 +00:00 committed by commit-bot@chromium.org
parent 57b192a0fc
commit 94be2fc1f8
2 changed files with 105 additions and 0 deletions

View file

@ -64,6 +64,34 @@ class ImportOrganizer {
var priority = getDirectivePriority(directive);
if (priority != null) {
var offset = directive.offset;
if (directive.beginToken.precedingComments != null) {
var firstComment = directive.beginToken.precedingComments;
var comment = firstComment;
// Don't connect comments that have a blank line between them
while (comment.next != null) {
var currentLine = lineInfo.getLocation(comment.offset).lineNumber;
var nextLine =
lineInfo.getLocation(comment.next.offset).lineNumber;
if (nextLine - currentLine > 1) {
firstComment = comment.next;
}
comment = comment.next;
}
// Check if the comment is the first comment in the document
if (firstComment != unit.beginToken.precedingComments) {
var previousLine = lineInfo
.getLocation(directive.beginToken.previous.end)
.lineNumber;
// Check if the comment is after the last token of the previous line
// Only connect, if it's not on the same line as the last token of the previous line
if (lineInfo.getLocation(firstComment.offset).lineNumber !=
previousLine) {
offset = firstComment.offset;
}
}
}
var end = directive.end;
var line = lineInfo.getLocation(end).lineNumber;

View file

@ -290,6 +290,53 @@ main() {
''');
}
Future<void>
test_sort_imports_dontConnectFirstCommentsWithBlankLinesBetween() async {
await _computeUnitAndErrors(r'''
// Copyright...
// Some comment related to the line below
import 'package:b/a.dart';
import 'package:a/b.dart';''');
_assertOrganize(r'''
// Copyright...
import 'package:a/b.dart';
// Some comment related to the line below
import 'package:b/a.dart';''');
}
Future<void> test_sort_imports_keepFirstCommentUntouched() async {
await _computeUnitAndErrors(r'''
// Copyright
// Copyright2
// Copyright3
import 'package:b/a.dart';
import 'package:a/b.dart';''');
_assertOrganize(r'''
// Copyright
// Copyright2
// Copyright3
import 'package:a/b.dart';
import 'package:b/a.dart';''');
}
Future<void> test_sort_imports_keepSubsequentComments() async {
await _computeUnitAndErrors(r'''
/// Copyright...
library lib;
import 'package:b/a.dart'; // We are keeping this because ...
import 'package:a/b.dart';''');
_assertOrganize(r'''
/// Copyright...
library lib;
import 'package:a/b.dart';
import 'package:b/a.dart'; // We are keeping this because ...''');
}
Future<void> test_sort_imports_packageAndPath() async {
await _computeUnitAndErrors(r'''
library lib;
@ -314,6 +361,36 @@ import 'package:product2.client/entity.dart';
''');
}
Future<void> test_sort_imports_with_library_keepPrecedingComments() async {
await _computeUnitAndErrors(r'''
/// Copyright...
library lib;
// Test comment
// We are keeping this because ... l1
// We are keeping this because ... l2
// We are keeping this because ... l3
import 'package:b/a.dart';
// Comment for a
import 'package:a/b.dart';''');
_assertOrganize(r'''
/// Copyright...
library lib;
// Test comment
// Comment for a
import 'package:a/b.dart';
// We are keeping this because ... l1
// We are keeping this because ... l2
// We are keeping this because ... l3
import 'package:b/a.dart';''');
}
void _assertOrganize(String expectedCode, {bool removeUnused = false}) {
var organizer = ImportOrganizer(testCode, testUnit, testErrors,
removeUnused: removeUnused);