Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit a030c64

Browse files
srawlinsCommit Queue
authored and
Commit Queue
committed
New fix: move_annotation_to_library_directive
Change-Id: Ifef0a4d5a9c81faf21a6cb39b5fb0fbb525db139 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/270780 Commit-Queue: Samuel Rawlins <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 4f37821 commit a030c64

File tree

7 files changed

+256
-3
lines changed

7 files changed

+256
-3
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:_fe_analyzer_shared/src/scanner/token.dart';
6+
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
7+
import 'package:analysis_server/src/services/correction/fix.dart';
8+
import 'package:analyzer/dart/analysis/features.dart';
9+
import 'package:analyzer/dart/ast/ast.dart';
10+
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
11+
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
12+
import 'package:analyzer_plugin/utilities/range_factory.dart';
13+
14+
class MoveAnnotationToLibraryDirective extends CorrectionProducer {
15+
@override
16+
FixKind get fixKind => DartFixKind.MOVE_ANNOTATION_TO_LIBRARY_DIRECTIVE;
17+
18+
@override
19+
Future<void> compute(ChangeBuilder builder) async {
20+
var annotation = node.thisOrAncestorOfType<Annotation>();
21+
if (annotation == null) {
22+
return;
23+
}
24+
var compilationUnit = annotation.root;
25+
if (compilationUnit is! CompilationUnit) {
26+
return;
27+
}
28+
29+
var firstDirective = compilationUnit.directives.isEmpty
30+
? null
31+
: compilationUnit.directives.first;
32+
if (firstDirective is LibraryDirective) {
33+
await _moveToExistingLibraryDirective(
34+
builder, annotation, firstDirective);
35+
return;
36+
}
37+
38+
if (!libraryElement.featureSet.isEnabled(Feature.unnamedLibraries)) {
39+
// If the library doesn't support unnamed libraries, then we cannot add
40+
// a new library directive; we don't know what to name it.
41+
return;
42+
}
43+
44+
await _moveToNewLibraryDirective(builder, annotation, compilationUnit);
45+
}
46+
47+
Future<void> _moveToExistingLibraryDirective(ChangeBuilder builder,
48+
Annotation annotation, LibraryDirective libraryDirective) async {
49+
// Just move the annotation to the existing library directive.
50+
var annotationRange = utils.getLinesRange(range.node(annotation));
51+
await builder.addDartFileEdit(file, (builder) {
52+
builder.addDeletion(annotationRange);
53+
var annotationText = utils.getRangeText(annotationRange);
54+
builder.addSimpleInsertion(
55+
libraryDirective.firstTokenAfterCommentAndMetadata.offset,
56+
annotationText);
57+
});
58+
}
59+
60+
Future<void> _moveToNewLibraryDirective(ChangeBuilder builder,
61+
Annotation annotation, CompilationUnit compilationUnit) async {
62+
var annotationRange = utils.getLinesRange(range.node(annotation));
63+
// Create a new, unnamed library directive, and move the annotation to just
64+
// above the directive.
65+
var token = compilationUnit.beginToken;
66+
67+
if (token.type == TokenType.SCRIPT_TAG) {
68+
// TODO(srawlins): Handle this case.
69+
return;
70+
}
71+
72+
if (token == annotation.beginToken) {
73+
// Do not "move" the annotation. Just slip a library directive below it.
74+
await builder.addDartFileEdit(file, (builder) {
75+
builder.addSimpleInsertion(annotationRange.end, 'library;$eol$eol');
76+
});
77+
return;
78+
}
79+
80+
int insertionOffset;
81+
String prefix;
82+
Token? commentOnFirstToken = token.precedingComments;
83+
if (commentOnFirstToken != null) {
84+
while (commentOnFirstToken!.next != null) {
85+
commentOnFirstToken = commentOnFirstToken.next!;
86+
}
87+
// `token` is now the last of the leading comments (perhaps a Copyight
88+
// notice, a Dart language version, etc.)
89+
insertionOffset = commentOnFirstToken.end;
90+
prefix = '$eol$eol';
91+
} else {
92+
insertionOffset = 0;
93+
prefix = '';
94+
}
95+
96+
await builder.addDartFileEdit(file, (builder) {
97+
builder.addDeletion(annotationRange);
98+
var annotationText = utils.getRangeText(annotationRange);
99+
builder.addSimpleInsertion(
100+
insertionOffset, '$prefix${annotationText}library;$eol$eol');
101+
});
102+
}
103+
}

pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
# - 710 "needsEvaluation"
2828
# - 282 for CompileTimeErrorCodes
2929
# - 220 for ParserErrorCodes
30-
# - 70 "needsFix"
31-
# - 298 "hasFix"
30+
# - 69 "needsFix"
31+
# - 299 "hasFix"
3232
# - 64 "noFix"
3333

3434
AnalysisOptionsErrorCode.INCLUDED_FILE_PARSE_ERROR:
@@ -1854,7 +1854,7 @@ LintCode.join_return_with_assignment:
18541854
LintCode.leading_newlines_in_multiline_strings:
18551855
status: hasFix
18561856
LintCode.library_annotations:
1857-
status: needsFix
1857+
status: hasFix
18581858
LintCode.library_names:
18591859
status: needsEvaluation
18601860
LintCode.library_prefixes:

pkg/analysis_server/lib/src/services/correction/fix.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,11 @@ class DartFixKind {
847847
DartFixKindPriority.DEFAULT,
848848
"Make '{0}' nullable",
849849
);
850+
static const MOVE_ANNOTATION_TO_LIBRARY_DIRECTIVE = FixKind(
851+
'dart.fix.moveAnnotationToLibraryDirective',
852+
DartFixKindPriority.DEFAULT,
853+
"Move this annotation to a library directive",
854+
);
850855
static const ORGANIZE_IMPORTS = FixKind(
851856
'dart.fix.organize.imports',
852857
DartFixKindPriority.DEFAULT,

pkg/analysis_server/lib/src/services/correction/fix_internal.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ import 'package:analysis_server/src/services/correction/dart/make_final.dart';
106106
import 'package:analysis_server/src/services/correction/dart/make_return_type_nullable.dart';
107107
import 'package:analysis_server/src/services/correction/dart/make_variable_not_final.dart';
108108
import 'package:analysis_server/src/services/correction/dart/make_variable_nullable.dart';
109+
import 'package:analysis_server/src/services/correction/dart/move_annotation_to_library_directive.dart';
109110
import 'package:analysis_server/src/services/correction/dart/move_type_arguments_to_class.dart';
110111
import 'package:analysis_server/src/services/correction/dart/organize_imports.dart';
111112
import 'package:analysis_server/src/services/correction/dart/qualify_reference.dart';
@@ -493,6 +494,9 @@ class FixProcessor extends BaseProcessor {
493494
LintNames.leading_newlines_in_multiline_strings: [
494495
AddLeadingNewlineToString.new,
495496
],
497+
LintNames.library_annotations: [
498+
MoveAnnotationToLibraryDirective.new,
499+
],
496500
LintNames.no_duplicate_case_values: [
497501
RemoveDuplicateCase.new,
498502
],

pkg/analysis_server/lib/src/services/linter/lint_names.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class LintNames {
6666
static const String implicit_call_tearoffs = 'implicit_call_tearoffs';
6767
static const String leading_newlines_in_multiline_strings =
6868
'leading_newlines_in_multiline_strings';
69+
static const String library_annotations = 'library_annotations';
6970
static const String no_duplicate_case_values = 'no_duplicate_case_values';
7071
static const String no_leading_underscores_for_library_prefixes =
7172
'no_leading_underscores_for_library_prefixes';
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:analysis_server/src/services/correction/fix.dart';
6+
import 'package:analysis_server/src/services/linter/lint_names.dart';
7+
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
8+
import 'package:test_reflective_loader/test_reflective_loader.dart';
9+
10+
import 'fix_processor.dart';
11+
12+
void main() {
13+
defineReflectiveSuite(() {
14+
defineReflectiveTests(MoveAnnotationToLibraryDirectiveTest);
15+
});
16+
}
17+
18+
@reflectiveTest
19+
class MoveAnnotationToLibraryDirectiveTest extends FixProcessorLintTest {
20+
@override
21+
FixKind get kind => DartFixKind.MOVE_ANNOTATION_TO_LIBRARY_DIRECTIVE;
22+
23+
@override
24+
String get lintCode => LintNames.library_annotations;
25+
26+
Future<void> test_existingLibraryDirective() async {
27+
await resolveTestCode('''
28+
/// Doc comment.
29+
library;
30+
@pragma('dart2js:late:trust')
31+
import 'dart:async';
32+
33+
void f(Completer c) {}
34+
''');
35+
await assertHasFix('''
36+
/// Doc comment.
37+
@pragma('dart2js:late:trust')
38+
library;
39+
import 'dart:async';
40+
41+
void f(Completer c) {}
42+
''');
43+
}
44+
45+
Future<void> test_noExistingLibraryDirective_annotationIsFirst() async {
46+
await resolveTestCode('''
47+
@pragma('dart2js:late:trust')
48+
import 'dart:async';
49+
50+
void f(Completer c) {}
51+
''');
52+
await assertHasFix('''
53+
@pragma('dart2js:late:trust')
54+
library;
55+
56+
import 'dart:async';
57+
58+
void f(Completer c) {}
59+
''');
60+
}
61+
62+
Future<void>
63+
test_noExistingLibraryDirective_annotherAnnotationIsFirst() async {
64+
await resolveTestCode('''
65+
@deprecated
66+
@pragma('dart2js:late:trust')
67+
import 'dart:async';
68+
69+
void f(Completer c) {}
70+
''');
71+
await assertHasFix('''
72+
@pragma('dart2js:late:trust')
73+
library;
74+
75+
@deprecated
76+
import 'dart:async';
77+
78+
void f(Completer c) {}
79+
''');
80+
}
81+
82+
Future<void> test_noExistingLibraryDirective_commentsAreFirst() async {
83+
await resolveTestCode('''
84+
// Comment 1.
85+
86+
// Comment 2.
87+
88+
@pragma('dart2js:late:trust')
89+
import 'dart:async';
90+
91+
void f(Completer c) {}
92+
''');
93+
await assertHasFix('''
94+
// Comment 1.
95+
96+
// Comment 2.
97+
98+
@pragma('dart2js:late:trust')
99+
library;
100+
101+
import 'dart:async';
102+
103+
void f(Completer c) {}
104+
''');
105+
}
106+
107+
Future<void>
108+
test_noExistingLibraryDirective_commentsAreFirst_andAnnotations() async {
109+
await resolveTestCode('''
110+
// Comment 1.
111+
112+
// Comment 2.
113+
114+
@deprecated
115+
@pragma('dart2js:late:trust')
116+
import 'dart:async';
117+
118+
void f(Completer c) {}
119+
''');
120+
// TODO(srawlins): Fix the 4 newlines below; should be 2.
121+
await assertHasFix('''
122+
// Comment 1.
123+
124+
// Comment 2.
125+
126+
@pragma('dart2js:late:trust')
127+
library;
128+
129+
130+
131+
@deprecated
132+
import 'dart:async';
133+
134+
void f(Completer c) {}
135+
''');
136+
}
137+
}

pkg/analysis_server/test/src/services/correction/fix/test_all.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ import 'make_final_test.dart' as make_final;
131131
import 'make_return_type_nullable_test.dart' as make_return_type_nullable;
132132
import 'make_variable_not_final_test.dart' as make_variable_not_final;
133133
import 'make_variable_nullable_test.dart' as make_variable_nullable;
134+
import 'move_annotation_to_library_directive_test.dart'
135+
as move_annotation_to_library_directive;
134136
import 'move_type_arguments_to_class_test.dart' as move_type_arguments_to_class;
135137
import 'organize_imports_test.dart' as organize_imports;
136138
import 'pubspec/test_all.dart' as pubspec;
@@ -359,6 +361,7 @@ void main() {
359361
make_return_type_nullable.main();
360362
make_variable_not_final.main();
361363
make_variable_nullable.main();
364+
move_annotation_to_library_directive.main();
362365
move_type_arguments_to_class.main();
363366
organize_imports.main();
364367
pubspec.main();

0 commit comments

Comments
 (0)