CQ. Update resolveTestCodeWithDiagnostics() to use removeDiagnosticExpectations().
Just as parser tests do. So, there is no interference with extra lines. Change-Id: I1d49d6d10c69fddc6b0632eeae10ed522c0cda57 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/505483 Commit-Queue: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Paul Berry <paulberry@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
026043d9ed
commit
da7f207611
@@ -4208,7 +4208,7 @@ void foo() {
|
||||
MethodInvocation
|
||||
target: SimpleIdentifier
|
||||
token: list
|
||||
element: list@237
|
||||
element: list@68
|
||||
staticType: List<dynamic>
|
||||
operator: .
|
||||
methodName: SimpleIdentifier
|
||||
@@ -4225,7 +4225,7 @@ MethodInvocation
|
||||
leftParenthesis: (
|
||||
parameter: RegularFormalParameter
|
||||
name: e
|
||||
declaredFragment: <testLibraryFragment> e@389
|
||||
declaredFragment: <testLibraryFragment> e@93
|
||||
element: hasImplicitType isPublic
|
||||
type: dynamic
|
||||
rightParenthesis: )
|
||||
@@ -4233,7 +4233,7 @@ MethodInvocation
|
||||
functionDefinition: =>
|
||||
expression: SimpleIdentifier
|
||||
token: e
|
||||
element: e@389
|
||||
element: e@93
|
||||
staticType: dynamic
|
||||
declaredFragment: <testLibraryFragment> null@null
|
||||
element: null@null
|
||||
@@ -4254,7 +4254,7 @@ MethodInvocation
|
||||
MethodInvocation
|
||||
target: SimpleIdentifier
|
||||
token: list
|
||||
element: list@237
|
||||
element: list@68
|
||||
staticType: List<dynamic>
|
||||
operator: .
|
||||
methodName: SimpleIdentifier
|
||||
@@ -4271,7 +4271,7 @@ MethodInvocation
|
||||
leftParenthesis: (
|
||||
parameter: RegularFormalParameter
|
||||
name: e
|
||||
declaredFragment: <testLibraryFragment> e@411
|
||||
declaredFragment: <testLibraryFragment> e@115
|
||||
element: hasImplicitType isPublic
|
||||
type: dynamic
|
||||
rightParenthesis: )
|
||||
@@ -4563,7 +4563,7 @@ MethodDeclaration
|
||||
typeParameters
|
||||
TypeParameter
|
||||
name: T
|
||||
declaredFragment: <testLibraryFragment> T@221
|
||||
declaredFragment: <testLibraryFragment> T@61
|
||||
defaultType: dynamic
|
||||
rightBracket: >
|
||||
parameters: FormalParameterList
|
||||
@@ -4574,7 +4574,7 @@ MethodDeclaration
|
||||
element: #E0 T
|
||||
type: T
|
||||
name: y
|
||||
declaredFragment: <testLibraryFragment> y@226
|
||||
declaredFragment: <testLibraryFragment> y@66
|
||||
element: isPublic
|
||||
type: T
|
||||
rightParenthesis: )
|
||||
@@ -4584,7 +4584,7 @@ MethodDeclaration
|
||||
literal: null
|
||||
staticType: Null
|
||||
semicolon: ;
|
||||
declaredFragment: <testLibraryFragment> f@219
|
||||
declaredFragment: <testLibraryFragment> f@59
|
||||
element: <testLibrary>::@class::D::@method::f
|
||||
type: T Function<T>(T)
|
||||
''');
|
||||
|
||||
@@ -172,7 +172,7 @@ ConstructorDeclaration
|
||||
thisKeyword: this
|
||||
period: .
|
||||
name: _x
|
||||
declaredFragment: <testLibraryFragment> x@103
|
||||
declaredFragment: <testLibraryFragment> x@31
|
||||
element: hasImplicitType isFinal isPublic
|
||||
type: int?
|
||||
field: <testLibrary>::@class::C::@field::_x
|
||||
|
||||
@@ -21,7 +21,7 @@ class EnumDeclarationResolutionTest extends PubPackageResolutionTest {
|
||||
await resolveTestCodeWithDiagnostics(r'''
|
||||
enum E {
|
||||
v(() {
|
||||
// [diag.constWithNonConstantArgument][column 5][length 193] Arguments of a constant creation must be constant expressions.
|
||||
// [diag.constWithNonConstantArgument][column 5][length 69] Arguments of a constant creation must be constant expressions.
|
||||
Object? x = 0;
|
||||
if (x is int) {
|
||||
x.isEven;
|
||||
@@ -1838,7 +1838,7 @@ FieldDeclaration
|
||||
token: foo
|
||||
element: <null>
|
||||
staticType: InvalidType
|
||||
declaredFragment: <testLibraryFragment> bar@206
|
||||
declaredFragment: <testLibraryFragment> bar@39
|
||||
semicolon: ;
|
||||
declaredFragment: <null>
|
||||
''');
|
||||
|
||||
@@ -2693,7 +2693,7 @@ ExtensionTypeDeclaration
|
||||
equals: =
|
||||
initializer: SimpleStringLiteral
|
||||
literal: 'not a type'
|
||||
declaredFragment: <testLibraryFragment> int@107
|
||||
declaredFragment: <testLibraryFragment> int@49
|
||||
semicolon: ;
|
||||
declaredFragment: <null>
|
||||
rightBracket: }
|
||||
|
||||
@@ -642,14 +642,14 @@ ForStatement
|
||||
equals: =
|
||||
initializer: SimpleStringLiteral
|
||||
literal: 'a'
|
||||
declaredFragment: isPublic i@152
|
||||
declaredFragment: isPublic i@61
|
||||
element: hasImplicitType isPublic
|
||||
type: String
|
||||
semicolon: ;
|
||||
ExpressionStatement
|
||||
expression: SimpleIdentifier
|
||||
token: i
|
||||
element: i@152
|
||||
element: i@61
|
||||
staticType: String
|
||||
semicolon: ;
|
||||
rightBracket: }
|
||||
@@ -1555,14 +1555,14 @@ ForStatement
|
||||
initializer: IntegerLiteral
|
||||
literal: 1
|
||||
staticType: int
|
||||
declaredFragment: isPublic a@165
|
||||
declaredFragment: isPublic a@67
|
||||
element: hasImplicitType isPublic
|
||||
type: int
|
||||
semicolon: ;
|
||||
ExpressionStatement
|
||||
expression: SimpleIdentifier
|
||||
token: a
|
||||
element: a@165
|
||||
element: a@67
|
||||
staticType: int
|
||||
semicolon: ;
|
||||
rightBracket: }
|
||||
@@ -2220,14 +2220,14 @@ ForStatement
|
||||
initializer: IntegerLiteral
|
||||
literal: 1
|
||||
staticType: int
|
||||
declaredFragment: isPublic a@145
|
||||
declaredFragment: isPublic a@53
|
||||
element: hasImplicitType isPublic
|
||||
type: int
|
||||
semicolon: ;
|
||||
ExpressionStatement
|
||||
expression: SimpleIdentifier
|
||||
token: a
|
||||
element: a@145
|
||||
element: a@53
|
||||
staticType: int
|
||||
semicolon: ;
|
||||
rightBracket: }
|
||||
|
||||
@@ -450,7 +450,7 @@ FormalParameterList
|
||||
leftParenthesis: (
|
||||
rightParenthesis: )
|
||||
question: ?
|
||||
declaredFragment: <testLibraryFragment> p2@118
|
||||
declaredFragment: <testLibraryFragment> p2@45
|
||||
element: isPublic
|
||||
type: void Function()?
|
||||
rightParenthesis: )
|
||||
@@ -472,7 +472,7 @@ FormalParameterList
|
||||
leftParenthesis: (
|
||||
rightParenthesis: )
|
||||
question: ?
|
||||
declaredFragment: <testLibraryFragment> p3@217
|
||||
declaredFragment: <testLibraryFragment> p3@71
|
||||
element: isPublic
|
||||
type: void Function()?
|
||||
rightDelimiter: }
|
||||
|
||||
+1
-1
@@ -142,7 +142,7 @@ void f() {
|
||||
assertResolvedNodeText(node, r'''
|
||||
SimpleIdentifier
|
||||
token: a
|
||||
element: a@149
|
||||
element: a@34
|
||||
staticType: InvalidType
|
||||
''');
|
||||
}
|
||||
|
||||
@@ -459,11 +459,12 @@ mixin ResolutionTest implements ResourceProviderMixin {
|
||||
/// Resolves [code] and checks that its inline diagnostic markers match the
|
||||
/// diagnostics. Unmarked code is expected to have no diagnostics.
|
||||
Future<void> resolveTestCodeWithDiagnostics(String code) async {
|
||||
addTestFile(code);
|
||||
var cleanCode = removeDiagnosticExpectations(code);
|
||||
addTestFile(cleanCode);
|
||||
await resolveTestFile();
|
||||
|
||||
var actual = updateExpectedDiagnostics(
|
||||
content: code,
|
||||
content: cleanCode,
|
||||
actualDiagnostics: result.diagnostics,
|
||||
);
|
||||
if (actual != code) {
|
||||
|
||||
@@ -1197,7 +1197,7 @@ SwitchStatement
|
||||
element: dart:core::@class::int
|
||||
type: int
|
||||
name: a
|
||||
declaredFragment: isPublic a@128
|
||||
declaredFragment: isPublic a@61
|
||||
element: isPublic
|
||||
type: int
|
||||
matchedValueType: Object?
|
||||
@@ -1206,7 +1206,7 @@ SwitchStatement
|
||||
expression: BinaryExpression
|
||||
leftOperand: SimpleIdentifier
|
||||
token: a
|
||||
element: a@128
|
||||
element: a@61
|
||||
staticType: int
|
||||
operator: >
|
||||
rightOperand: IntegerLiteral
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../dart/resolution/context_collection_resolution.dart';
|
||||
import '../dart/resolution/node_text_expectations.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(DeadCodeTest);
|
||||
defineReflectiveTests(DeadCodeTest_Language219);
|
||||
defineReflectiveTests(DeadCodeTest_AnonymousMethodsExperiment);
|
||||
defineReflectiveTests(UpdateNodeTextExpectations);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -194,7 +196,7 @@ Never foo() => throw "Never";
|
||||
test() {
|
||||
int i = 0;
|
||||
for (foo(); (i = 42) < 0;) {}
|
||||
// [diag.deadCode][column 15][length 81] Dead code.
|
||||
// [diag.deadCode][column 15][length 29] Dead code.
|
||||
return i;
|
||||
}
|
||||
''');
|
||||
@@ -551,7 +553,7 @@ class C {
|
||||
class A {
|
||||
int x;
|
||||
A() : x = throw 0 {
|
||||
// [diag.deadCode][column 21][length 64] Dead code.
|
||||
// [diag.deadCode][column 21][length 12] Dead code.
|
||||
x;
|
||||
}
|
||||
}
|
||||
@@ -1072,7 +1074,7 @@ void f(bool c) {
|
||||
// ^^^^^^^^^^^^
|
||||
// [diag.deadCode] Dead code.
|
||||
print('');
|
||||
// [diag.deadCode][column 5][length 89] Dead code.
|
||||
// [diag.deadCode][column 5][length 38] Dead code.
|
||||
} while (c);
|
||||
print('');
|
||||
}
|
||||
@@ -1092,7 +1094,7 @@ void f(bool c) {
|
||||
// ^^^^^^^^^^^^
|
||||
// [diag.deadCode] Dead code.
|
||||
print('');
|
||||
// [diag.deadCode][column 5][length 65] Dead code.
|
||||
// [diag.deadCode][column 5][length 14] Dead code.
|
||||
}
|
||||
}
|
||||
''');
|
||||
@@ -1521,7 +1523,7 @@ void f() {
|
||||
{
|
||||
return;
|
||||
2;
|
||||
// [diag.deadCode][column 7][length 59] Dead code.
|
||||
// [diag.deadCode][column 7][length 8] Dead code.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1585,7 +1587,7 @@ main() {
|
||||
2;
|
||||
return;
|
||||
3;
|
||||
// [diag.deadCode][column 5][length 62] Dead code.
|
||||
// [diag.deadCode][column 5][length 11] Dead code.
|
||||
}
|
||||
4;
|
||||
}
|
||||
@@ -1607,7 +1609,7 @@ void f() {
|
||||
await resolveTestCodeWithDiagnostics(r'''
|
||||
void f() {
|
||||
if (false) {
|
||||
// [diag.deadCode][column 14][length 64] Dead code.
|
||||
// [diag.deadCode][column 14][length 12] Dead code.
|
||||
1;
|
||||
} else {
|
||||
2;
|
||||
@@ -1623,7 +1625,7 @@ void f() {
|
||||
if (true) {
|
||||
1;
|
||||
} else {
|
||||
// [diag.deadCode][column 10][length 64] Dead code.
|
||||
// [diag.deadCode][column 10][length 12] Dead code.
|
||||
2;
|
||||
}
|
||||
3;
|
||||
@@ -1640,7 +1642,7 @@ void g(A a) {
|
||||
a.f(0);
|
||||
//^^^
|
||||
// [diag.receiverOfTypeNever] The receiver is of type 'Never', and will never complete with a value.
|
||||
// [diag.deadCode][column 6][length 175] Dead code.
|
||||
// [diag.deadCode][column 6][length 16] Dead code.
|
||||
print(1);
|
||||
}
|
||||
''');
|
||||
@@ -1652,7 +1654,7 @@ void g(Never f) {
|
||||
(f)(0);
|
||||
//^^^
|
||||
// [diag.receiverOfTypeNever] The receiver is of type 'Never', and will never complete with a value.
|
||||
// [diag.deadCode][column 6][length 175] Dead code.
|
||||
// [diag.deadCode][column 6][length 16] Dead code.
|
||||
print(1);
|
||||
}
|
||||
''');
|
||||
@@ -1664,7 +1666,7 @@ void g(Never f) {
|
||||
f(0);
|
||||
//^
|
||||
// [diag.receiverOfTypeNever] The receiver is of type 'Never', and will never complete with a value.
|
||||
// [diag.deadCode][column 4][length 173] Dead code.
|
||||
// [diag.deadCode][column 4][length 16] Dead code.
|
||||
print(1);
|
||||
}
|
||||
''');
|
||||
@@ -1992,7 +1994,7 @@ f() {
|
||||
print(1);
|
||||
return;
|
||||
print(2);
|
||||
// [diag.deadCode][column 3][length 82] Dead code.
|
||||
// [diag.deadCode][column 3][length 31] Dead code.
|
||||
return;
|
||||
print(3);
|
||||
}
|
||||
|
||||
@@ -44,8 +44,6 @@ void f() {
|
||||
// ^^^^^^^^^^^^^^^^^^^^^
|
||||
// [diag.duplicateIgnore] The diagnostic 'unused_local_variable' doesn't need to be ignored here because it's already being ignored.
|
||||
var x = 0;
|
||||
// ^
|
||||
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
|
||||
}
|
||||
''');
|
||||
}
|
||||
@@ -78,8 +76,6 @@ void f() {}
|
||||
// ^^^^^^^^^
|
||||
// [diag.duplicateIgnore] The diagnostic 'lint' doesn't need to be ignored here because it's already being ignored.
|
||||
void g(arg1(int)) {} // AVOID_TYPES_AS_PARAMETER_NAMES
|
||||
// ^^^
|
||||
// [diag.avoidTypesAsParameterNamesFormalParameter] The parameter name 'int' matches a visible type name.
|
||||
''');
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,13 @@ import 'package:analyzer/src/diagnostic/diagnostic.dart' as diag;
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../dart/resolution/context_collection_resolution.dart';
|
||||
import '../dart/resolution/node_text_expectations.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(ForInOfInvalidTypeTest);
|
||||
defineReflectiveTests(ForInOfInvalidTypeWithStrictCastsTest);
|
||||
defineReflectiveTests(UpdateNodeTextExpectations);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -44,7 +46,7 @@ f(bool e) async {
|
||||
await resolveTestCodeWithDiagnostics(r'''
|
||||
f(Never e) async {
|
||||
await for (var id in e) {
|
||||
// [diag.deadCode][column 14][length 78] Dead code.
|
||||
// [diag.deadCode][column 14][length 26] Dead code.
|
||||
id;
|
||||
}
|
||||
}
|
||||
@@ -135,7 +137,7 @@ f(L e) {
|
||||
await resolveTestCodeWithDiagnostics(r'''
|
||||
f(Never e) {
|
||||
for (var id in e) {
|
||||
// [diag.deadCode][column 8][length 77] Dead code.
|
||||
// [diag.deadCode][column 8][length 26] Dead code.
|
||||
id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ GuardedPattern
|
||||
pattern: DeclaredVariablePattern
|
||||
keyword: final
|
||||
name: b
|
||||
declaredFragment: isFinal isPublic b@160
|
||||
declaredFragment: isFinal isPublic b@61
|
||||
element: hasImplicitType isFinal isPublic
|
||||
type: int
|
||||
matchedValueType: int
|
||||
@@ -84,7 +84,7 @@ GuardedPattern
|
||||
pattern: DeclaredVariablePattern
|
||||
keyword: final
|
||||
name: b
|
||||
declaredFragment: isFinal isPublic b@159
|
||||
declaredFragment: isFinal isPublic b@60
|
||||
element: hasImplicitType isFinal isPublic
|
||||
type: int
|
||||
matchedValueType: int
|
||||
@@ -692,7 +692,7 @@ GuardedPattern
|
||||
pattern: DeclaredVariablePattern
|
||||
keyword: final
|
||||
name: a
|
||||
declaredFragment: isFinal isPublic a@177
|
||||
declaredFragment: isFinal isPublic a@76
|
||||
element: hasImplicitType isFinal isPublic
|
||||
type: int
|
||||
matchedValueType: int
|
||||
|
||||
+2
-2
@@ -805,7 +805,7 @@ main() {
|
||||
void f() {
|
||||
int v;
|
||||
if (false) {
|
||||
// [diag.deadCode][column 14][length 77] Dead code.
|
||||
// [diag.deadCode][column 14][length 25] Dead code.
|
||||
// not assigned
|
||||
} else {
|
||||
v = 0;
|
||||
@@ -868,7 +868,7 @@ void f() {
|
||||
void f() {
|
||||
int v;
|
||||
if (!true) {
|
||||
// [diag.deadCode][column 14][length 77] Dead code.
|
||||
// [diag.deadCode][column 14][length 25] Dead code.
|
||||
// not assigned
|
||||
} else {
|
||||
v = 0;
|
||||
|
||||
@@ -33,7 +33,7 @@ void f() {
|
||||
assertResolvedNodeText(node, r'''
|
||||
SimpleIdentifier
|
||||
token: v
|
||||
element: v@149
|
||||
element: v@34
|
||||
staticType: InvalidType
|
||||
''');
|
||||
}
|
||||
@@ -168,7 +168,7 @@ void f(int a) {
|
||||
assertResolvedNodeText(node, r'''
|
||||
SimpleIdentifier
|
||||
token: v
|
||||
element: v@194
|
||||
element: v@75
|
||||
staticType: void Function()
|
||||
''');
|
||||
}
|
||||
@@ -195,7 +195,7 @@ void f(int a) {
|
||||
assertResolvedNodeText(node, r'''
|
||||
SimpleIdentifier
|
||||
token: v
|
||||
element: v@210
|
||||
element: v@91
|
||||
staticType: void Function()
|
||||
''');
|
||||
}
|
||||
@@ -221,7 +221,7 @@ void f(int a) {
|
||||
assertResolvedNodeText(node, r'''
|
||||
SimpleIdentifier
|
||||
token: v
|
||||
element: v@193
|
||||
element: v@74
|
||||
staticType: dynamic
|
||||
''');
|
||||
}
|
||||
@@ -248,7 +248,7 @@ void f(int a) {
|
||||
assertResolvedNodeText(node, r'''
|
||||
SimpleIdentifier
|
||||
token: v
|
||||
element: v@209
|
||||
element: v@90
|
||||
staticType: dynamic
|
||||
''');
|
||||
}
|
||||
@@ -274,7 +274,7 @@ void f(int a) {
|
||||
assertResolvedNodeText(node, r'''
|
||||
SimpleIdentifier
|
||||
token: v
|
||||
element: v@195
|
||||
element: v@76
|
||||
staticType: void Function()
|
||||
''');
|
||||
}
|
||||
@@ -301,7 +301,7 @@ void f(int a) {
|
||||
assertResolvedNodeText(node, r'''
|
||||
SimpleIdentifier
|
||||
token: v
|
||||
element: v@211
|
||||
element: v@92
|
||||
staticType: void Function()
|
||||
''');
|
||||
}
|
||||
@@ -327,7 +327,7 @@ void f(int a) {
|
||||
assertResolvedNodeText(node, r'''
|
||||
SimpleIdentifier
|
||||
token: v
|
||||
element: v@194
|
||||
element: v@75
|
||||
staticType: dynamic
|
||||
''');
|
||||
}
|
||||
@@ -354,7 +354,7 @@ void f(int a) {
|
||||
assertResolvedNodeText(node, r'''
|
||||
SimpleIdentifier
|
||||
token: v
|
||||
element: v@210
|
||||
element: v@91
|
||||
staticType: dynamic
|
||||
''');
|
||||
}
|
||||
|
||||
@@ -41,8 +41,9 @@ String removeTrailingLineTerminator(String content) {
|
||||
|
||||
/// Returns [content] with canonical diagnostic expectation markers.
|
||||
///
|
||||
/// Existing diagnostic expectation marker lines are removed before the new
|
||||
/// markers are inserted, so [content] can be either unmarked or already marked.
|
||||
/// The [content] must not include diagnostic expectation marker lines. Use
|
||||
/// [removeDiagnosticExpectations] before analysis, and pass the analyzed
|
||||
/// content here.
|
||||
String updateExpectedDiagnostics({
|
||||
required String content,
|
||||
required List<Diagnostic> actualDiagnostics,
|
||||
@@ -60,7 +61,16 @@ final class _ExpectedDiagnosticsUpdater {
|
||||
|
||||
_ExpectedDiagnosticsUpdater(String content)
|
||||
: lines = _Line.parse(content),
|
||||
lineInfo = LineInfo.fromContent(content);
|
||||
lineInfo = LineInfo.fromContent(content) {
|
||||
for (var line in lines) {
|
||||
if (_LineMarker.isMarker(line)) {
|
||||
throw StateError(
|
||||
'Expected content without diagnostic expectation markers, '
|
||||
'found one on line ${line.number}.',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String update(List<Diagnostic> actualDiagnostics) {
|
||||
_generateMarkers(actualDiagnostics);
|
||||
@@ -90,10 +100,7 @@ final class _ExpectedDiagnosticsUpdater {
|
||||
|
||||
var id = nextContextId++;
|
||||
contextRefs.add(id);
|
||||
var location = _markerLocation(
|
||||
offset: contextMessage.offset,
|
||||
length: contextMessage.length,
|
||||
);
|
||||
var location = _markerLocation(offset: contextMessage.offset);
|
||||
var line = lines[location.lineNumber - 1];
|
||||
var presentation = _markerPresentation(
|
||||
line,
|
||||
@@ -115,10 +122,7 @@ final class _ExpectedDiagnosticsUpdater {
|
||||
);
|
||||
}
|
||||
|
||||
var location = _markerLocation(
|
||||
offset: diagnostic.offset,
|
||||
length: diagnostic.length,
|
||||
);
|
||||
var location = _markerLocation(offset: diagnostic.offset);
|
||||
var line = lines[location.lineNumber - 1];
|
||||
var presentation = _markerPresentation(
|
||||
line,
|
||||
@@ -150,32 +154,8 @@ final class _ExpectedDiagnosticsUpdater {
|
||||
}
|
||||
|
||||
/// Returns where a generated marker should be written for an actual range.
|
||||
///
|
||||
/// For a normal diagnostic range, the marker belongs on the line reported by
|
||||
/// [LineInfo]. For a zero-length diagnostic, the diagnostic is often an
|
||||
/// insertion point rather than a source span. If the input is already
|
||||
/// marked, that insertion point can be pushed into the existing marker
|
||||
/// comments, or to the empty line after them, even though the marker should
|
||||
/// still be attached to the preceding real source line. In that case, keep
|
||||
/// the marker on the source line and express the insertion point as the
|
||||
/// column after its last character.
|
||||
({int lineNumber, int column}) _markerLocation({
|
||||
required int offset,
|
||||
required int length,
|
||||
}) {
|
||||
({int lineNumber, int column}) _markerLocation({required int offset}) {
|
||||
var location = lineInfo.getLocation(offset);
|
||||
if (length == 0) {
|
||||
// Only zero-length diagnostics can legitimately move onto marker-only
|
||||
// text from a previous update. A non-zero range on a marker line would
|
||||
// describe the marker comment itself, not an insertion point in code.
|
||||
var targetLine = _targetLineForMarkerShift(location.lineNumber);
|
||||
if (targetLine != null) {
|
||||
return (
|
||||
lineNumber: targetLine.number,
|
||||
column: targetLine.text.length + 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
return (lineNumber: location.lineNumber, column: location.columnNumber);
|
||||
}
|
||||
|
||||
@@ -204,59 +184,10 @@ final class _ExpectedDiagnosticsUpdater {
|
||||
);
|
||||
}
|
||||
|
||||
/// Finds the real source line that owns a shifted zero-length marker.
|
||||
///
|
||||
/// The updater accepts both clean source and source that already contains
|
||||
/// diagnostic expectation comments. Existing marker comments are removed when
|
||||
/// the new content is written, but actual diagnostics are computed before
|
||||
/// that removal. This matters for zero-length diagnostics near the end of a
|
||||
/// line or file: after a previous update, the analyzer may report the same
|
||||
/// insertion point as being on a marker line, or on the empty line
|
||||
/// immediately following marker lines.
|
||||
///
|
||||
/// This method recognizes only those shifted positions. If [lineNumber]
|
||||
/// points at ordinary source text, or at an empty line that is not directly
|
||||
/// after a marker, there is nothing to repair and `null` is returned.
|
||||
/// Otherwise the search walks backward over marker lines and returns the
|
||||
/// nearest preceding non-marker line, which is where the regenerated marker
|
||||
/// should be attached.
|
||||
_Line? _targetLineForMarkerShift(int lineNumber) {
|
||||
if (lineNumber < 1 || lineNumber > lines.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var line = lines[lineNumber - 1];
|
||||
if (!_LineMarker.isMarker(line)) {
|
||||
// A non-marker line normally owns the reported offset. The one exception
|
||||
// is the synthetic empty line after existing markers, which can be where
|
||||
// EOF-style zero-length diagnostics land.
|
||||
var previousLine = lineNumber > 1 ? lines[lineNumber - 2] : null;
|
||||
if (line.text.isNotEmpty ||
|
||||
previousLine == null ||
|
||||
!_LineMarker.isMarker(previousLine)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// The reported line is either a marker line or the empty line just after
|
||||
// marker lines. Walk back to the line these markers annotate.
|
||||
for (var index = lineNumber - 2; index >= 0; index--) {
|
||||
var previousLine = lines[index];
|
||||
if (!_LineMarker.isMarker(previousLine)) {
|
||||
return previousLine;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String _writeContent() {
|
||||
var buffer = StringBuffer();
|
||||
var isFirstLine = true;
|
||||
for (var line in lines) {
|
||||
if (_LineMarker.isMarker(line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isFirstLine) {
|
||||
isFirstLine = false;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user