mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 21:20:36 +00:00
Record elements and types parts of missing patterns for AddMissingSwitchCases fix.
Bug: https://github.com/dart-lang/sdk/issues/51985 Change-Id: I48e04e992ccab5cb5dedb5df328ba13ffcf6b560 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/302200 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
b1c110bd17
commit
4f7295ad26
|
@ -5,7 +5,10 @@
|
|||
import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
|
||||
import 'package:analysis_server/src/services/correction/fix.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/error/error.dart';
|
||||
import 'package:analyzer/src/generated/exhaustiveness.dart';
|
||||
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
|
||||
import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
|
||||
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
|
||||
|
||||
class AddMissingSwitchCases extends CorrectionProducer {
|
||||
|
@ -22,8 +25,13 @@ class AddMissingSwitchCases extends CorrectionProducer {
|
|||
Future<void> compute(ChangeBuilder builder) async {
|
||||
final node = this.node;
|
||||
|
||||
final patternCode = _patternSuggestion();
|
||||
if (patternCode == null) {
|
||||
final diagnostic = this.diagnostic;
|
||||
if (diagnostic is! AnalysisError) {
|
||||
return;
|
||||
}
|
||||
|
||||
final patternParts = diagnostic.data;
|
||||
if (patternParts is! List<MissingPatternPart>) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -31,7 +39,7 @@ class AddMissingSwitchCases extends CorrectionProducer {
|
|||
await _switchExpression(
|
||||
builder: builder,
|
||||
node: node,
|
||||
patternCode: patternCode,
|
||||
patternParts: patternParts,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -39,38 +47,15 @@ class AddMissingSwitchCases extends CorrectionProducer {
|
|||
await _switchStatement(
|
||||
builder: builder,
|
||||
node: node,
|
||||
patternCode: patternCode,
|
||||
patternParts: patternParts,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the pattern code suggestion from the correction message.
|
||||
///
|
||||
/// TODO(scheglov) In general, this code might be not always valid code.
|
||||
String? _patternSuggestion() {
|
||||
final diagnostic = this.diagnostic;
|
||||
if (diagnostic == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final correctionMessage = diagnostic.correctionMessage;
|
||||
if (correctionMessage == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final regExp = RegExp("that match '(.+)'");
|
||||
final match = regExp.firstMatch(correctionMessage);
|
||||
if (match == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return match.group(1);
|
||||
}
|
||||
|
||||
Future<void> _switchExpression({
|
||||
required ChangeBuilder builder,
|
||||
required SwitchExpression node,
|
||||
required String patternCode,
|
||||
required List<MissingPatternPart> patternParts,
|
||||
}) async {
|
||||
final lineIndent = utils.getLinePrefix(node.offset);
|
||||
final singleIndent = utils.getIndent(1);
|
||||
|
@ -88,7 +73,7 @@ class AddMissingSwitchCases extends CorrectionProducer {
|
|||
builder.writeln('// TODO: Handle this case.');
|
||||
builder.write(lineIndent);
|
||||
builder.write(singleIndent);
|
||||
builder.write(patternCode);
|
||||
_writePatternParts(builder, patternParts);
|
||||
builder.writeln(' => null,');
|
||||
builder.write(location.suffix);
|
||||
});
|
||||
|
@ -98,7 +83,7 @@ class AddMissingSwitchCases extends CorrectionProducer {
|
|||
Future<void> _switchStatement({
|
||||
required ChangeBuilder builder,
|
||||
required SwitchStatement node,
|
||||
required String patternCode,
|
||||
required List<MissingPatternPart> patternParts,
|
||||
}) async {
|
||||
final lineIndent = utils.getLinePrefix(node.offset);
|
||||
final singleIndent = utils.getIndent(1);
|
||||
|
@ -114,7 +99,7 @@ class AddMissingSwitchCases extends CorrectionProducer {
|
|||
builder.write(lineIndent);
|
||||
builder.write(singleIndent);
|
||||
builder.write('case ');
|
||||
builder.write(patternCode);
|
||||
_writePatternParts(builder, patternParts);
|
||||
builder.writeln(':');
|
||||
builder.write(lineIndent);
|
||||
builder.write(singleIndent);
|
||||
|
@ -124,4 +109,21 @@ class AddMissingSwitchCases extends CorrectionProducer {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
void _writePatternParts(
|
||||
DartEditBuilder builder,
|
||||
List<MissingPatternPart> parts,
|
||||
) {
|
||||
for (final part in parts) {
|
||||
if (part is MissingPatternEnumValuePart) {
|
||||
builder.writeReference(part.enumElement);
|
||||
builder.write('.');
|
||||
builder.write(part.value.name);
|
||||
} else if (part is MissingPatternTextPart) {
|
||||
builder.write(part.text);
|
||||
} else if (part is MissingPatternTypePart) {
|
||||
builder.writeType(part.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -347,6 +347,9 @@ class MockAnalysisError implements engine.AnalysisError {
|
|||
@override
|
||||
String? get correctionMessage => _correctionMessage;
|
||||
|
||||
@override
|
||||
Object? get data => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
engine.ErrorCode get errorCode => _errorCode!;
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analysis_server/src/services/correction/fix.dart';
|
||||
import 'package:analysis_server/src/services/linter/lint_names.dart';
|
||||
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
|
@ -10,16 +11,55 @@ import 'fix_processor.dart';
|
|||
|
||||
void main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(AddMissingSwitchCasesTest);
|
||||
defineReflectiveTests(AddMissingSwitchCasesTest_SwitchExpression);
|
||||
defineReflectiveTests(AddMissingSwitchCasesTest_SwitchStatement);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class AddMissingSwitchCasesTest extends FixProcessorTest {
|
||||
class AddMissingSwitchCasesTest_SwitchExpression extends FixProcessorTest {
|
||||
@override
|
||||
FixKind get kind => DartFixKind.ADD_MISSING_SWITCH_CASES;
|
||||
|
||||
Future<void> test_switchExpression_enum_hasFirst() async {
|
||||
Future<void> test_bool_hasFalse() async {
|
||||
await resolveTestCode('''
|
||||
int f(bool x) {
|
||||
return switch (x) {
|
||||
false => 0,
|
||||
};
|
||||
}
|
||||
''');
|
||||
await assertHasFix('''
|
||||
int f(bool x) {
|
||||
return switch (x) {
|
||||
false => 0,
|
||||
// TODO: Handle this case.
|
||||
true => null,
|
||||
};
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_bool_hasTrue() async {
|
||||
await resolveTestCode('''
|
||||
int f(bool x) {
|
||||
return switch (x) {
|
||||
true => 0,
|
||||
};
|
||||
}
|
||||
''');
|
||||
await assertHasFix('''
|
||||
int f(bool x) {
|
||||
return switch (x) {
|
||||
true => 0,
|
||||
// TODO: Handle this case.
|
||||
false => null,
|
||||
};
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_enum_hasFirst() async {
|
||||
await resolveTestCode('''
|
||||
enum E {
|
||||
first, second, third
|
||||
|
@ -46,7 +86,74 @@ int f(E x) {
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_switchExpression_num_anyDouble_intProperty() async {
|
||||
Future<void> test_enum_importedWithPrefix() async {
|
||||
newFile('$testPackageLibPath/a.dart', r'''
|
||||
enum E {
|
||||
first, second, third
|
||||
}
|
||||
''');
|
||||
|
||||
await resolveTestCode('''
|
||||
import 'a.dart' as prefix;
|
||||
|
||||
int f(prefix.E x) {
|
||||
return switch (x) {
|
||||
};
|
||||
}
|
||||
''');
|
||||
await assertHasFix('''
|
||||
import 'a.dart' as prefix;
|
||||
|
||||
int f(prefix.E x) {
|
||||
return switch (x) {
|
||||
// TODO: Handle this case.
|
||||
prefix.E.first => null,
|
||||
};
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_enum_notImported() async {
|
||||
newFile('$testPackageLibPath/a.dart', r'''
|
||||
enum E {
|
||||
first, second, third
|
||||
}
|
||||
''');
|
||||
|
||||
newFile('$testPackageLibPath/b.dart', r'''
|
||||
import 'a.dart';
|
||||
|
||||
var value = E.first;
|
||||
''');
|
||||
|
||||
createAnalysisOptionsFile(
|
||||
lints: [
|
||||
LintNames.prefer_relative_imports,
|
||||
],
|
||||
);
|
||||
|
||||
await resolveTestCode('''
|
||||
import 'b.dart';
|
||||
|
||||
int f() {
|
||||
return switch (value) {
|
||||
};
|
||||
}
|
||||
''');
|
||||
await assertHasFix('''
|
||||
import 'a.dart';
|
||||
import 'b.dart';
|
||||
|
||||
int f() {
|
||||
return switch (value) {
|
||||
// TODO: Handle this case.
|
||||
E.first => null,
|
||||
};
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_num_anyDouble_intProperty() async {
|
||||
await resolveTestCode('''
|
||||
int f(num x) {
|
||||
return switch (x) {
|
||||
|
@ -67,7 +174,7 @@ int f(num x) {
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_switchExpression_num_doubleAny() async {
|
||||
Future<void> test_num_doubleAny() async {
|
||||
await resolveTestCode('''
|
||||
int f(num x) {
|
||||
return switch (x) {
|
||||
|
@ -86,7 +193,30 @@ int f(num x) {
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_switchExpression_num_doubleAny_intWhen() async {
|
||||
Future<void> test_num_doubleAny_coreWithPrefix() async {
|
||||
await resolveTestCode('''
|
||||
import 'dart:core' as core;
|
||||
|
||||
core.int f(core.num x) {
|
||||
return switch (x) {
|
||||
core.double() => 0,
|
||||
};
|
||||
}
|
||||
''');
|
||||
await assertHasFix('''
|
||||
import 'dart:core' as core;
|
||||
|
||||
core.int f(core.num x) {
|
||||
return switch (x) {
|
||||
core.double() => 0,
|
||||
// TODO: Handle this case.
|
||||
core.int() => null,
|
||||
};
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_num_doubleAny_intWhen() async {
|
||||
await resolveTestCode('''
|
||||
int f(num x) {
|
||||
return switch (x) {
|
||||
|
@ -107,7 +237,7 @@ int f(num x) {
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_switchExpression_num_empty() async {
|
||||
Future<void> test_num_empty() async {
|
||||
await resolveTestCode('''
|
||||
int f(num x) {
|
||||
return switch (x) {};
|
||||
|
@ -122,8 +252,14 @@ int f(num x) {
|
|||
}
|
||||
''');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> test_switchStatement_num_doubleAny() async {
|
||||
@reflectiveTest
|
||||
class AddMissingSwitchCasesTest_SwitchStatement extends FixProcessorTest {
|
||||
@override
|
||||
FixKind get kind => DartFixKind.ADD_MISSING_SWITCH_CASES;
|
||||
|
||||
Future<void> test_num_doubleAny() async {
|
||||
await resolveTestCode('''
|
||||
void f(num x) {
|
||||
switch (x) {
|
||||
|
@ -144,7 +280,7 @@ void f(num x) {
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_switchStatement_num_doubleAny_intProperty() async {
|
||||
Future<void> test_num_doubleAny_intProperty() async {
|
||||
await resolveTestCode('''
|
||||
void f(num x) {
|
||||
switch (x) {
|
||||
|
@ -169,7 +305,7 @@ void f(num x) {
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_switchStatement_num_empty() async {
|
||||
Future<void> test_num_empty() async {
|
||||
await resolveTestCode('''
|
||||
void f(num x) {
|
||||
switch (x) {}
|
||||
|
|
|
@ -84,6 +84,9 @@ class AnalysisError implements Diagnostic {
|
|||
/// if there are no context messages.
|
||||
final List<DiagnosticMessage> _contextMessages;
|
||||
|
||||
/// Data associated with this error, specific for [errorCode].
|
||||
final Object? data;
|
||||
|
||||
/// The correction to be displayed for this error, or `null` if there is no
|
||||
/// correction information for this error.
|
||||
String? _correctionMessage;
|
||||
|
@ -104,6 +107,7 @@ class AnalysisError implements Diagnostic {
|
|||
ErrorCode errorCode, [
|
||||
List<Object?>? arguments,
|
||||
List<DiagnosticMessage> contextMessages = const [],
|
||||
Object? data,
|
||||
]) {
|
||||
return AnalysisError.tmp(
|
||||
source: source,
|
||||
|
@ -112,6 +116,7 @@ class AnalysisError implements Diagnostic {
|
|||
errorCode: errorCode,
|
||||
arguments: arguments ?? const [],
|
||||
contextMessages: contextMessages,
|
||||
data: data,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -124,6 +129,7 @@ class AnalysisError implements Diagnostic {
|
|||
required String message,
|
||||
String? correctionMessage,
|
||||
List<DiagnosticMessage> contextMessages = const [],
|
||||
this.data,
|
||||
}) : _correctionMessage = correctionMessage,
|
||||
_contextMessages = contextMessages {
|
||||
_problemMessage = DiagnosticMessageImpl(
|
||||
|
@ -147,6 +153,7 @@ class AnalysisError implements Diagnostic {
|
|||
required this.errorCode,
|
||||
List<Object?> arguments = const [],
|
||||
List<DiagnosticMessage> contextMessages = const [],
|
||||
this.data,
|
||||
}) : _contextMessages = contextMessages {
|
||||
assert(
|
||||
arguments.length == errorCode.numParameters,
|
||||
|
|
|
@ -97,16 +97,27 @@ class ErrorReporter {
|
|||
|
||||
/// Report an error with the given [errorCode] and [arguments].
|
||||
/// The [node] is used to compute the location of the error.
|
||||
void reportErrorForNode(ErrorCode errorCode, AstNode node,
|
||||
[List<Object>? arguments, List<DiagnosticMessage>? messages]) {
|
||||
void reportErrorForNode(
|
||||
ErrorCode errorCode,
|
||||
AstNode node, [
|
||||
List<Object>? arguments,
|
||||
List<DiagnosticMessage>? messages,
|
||||
Object? data,
|
||||
]) {
|
||||
reportErrorForOffset(
|
||||
errorCode, node.offset, node.length, arguments, messages);
|
||||
errorCode, node.offset, node.length, arguments, messages, data);
|
||||
}
|
||||
|
||||
/// Report an error with the given [errorCode] and [arguments]. The location
|
||||
/// of the error is specified by the given [offset] and [length].
|
||||
void reportErrorForOffset(ErrorCode errorCode, int offset, int length,
|
||||
[List<Object>? arguments, List<DiagnosticMessage>? messages]) {
|
||||
void reportErrorForOffset(
|
||||
ErrorCode errorCode,
|
||||
int offset,
|
||||
int length, [
|
||||
List<Object>? arguments,
|
||||
List<DiagnosticMessage>? messages,
|
||||
Object? data,
|
||||
]) {
|
||||
if (lockLevel != 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -122,6 +133,7 @@ class ErrorReporter {
|
|||
errorCode: errorCode,
|
||||
arguments: arguments ?? const [],
|
||||
contextMessages: messages,
|
||||
data: data,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -135,10 +147,15 @@ class ErrorReporter {
|
|||
|
||||
/// Report an error with the given [errorCode] and [arguments]. The [token] is
|
||||
/// used to compute the location of the error.
|
||||
void reportErrorForToken(ErrorCode errorCode, Token token,
|
||||
[List<Object>? arguments, List<DiagnosticMessage>? messages]) {
|
||||
void reportErrorForToken(
|
||||
ErrorCode errorCode,
|
||||
Token token, [
|
||||
List<Object>? arguments,
|
||||
List<DiagnosticMessage>? messages,
|
||||
Object? data,
|
||||
]) {
|
||||
reportErrorForOffset(
|
||||
errorCode, token.offset, token.length, arguments, messages);
|
||||
errorCode, token.offset, token.length, arguments, messages, data);
|
||||
}
|
||||
|
||||
/// Report an error with the given [errorCode] and [arguments]. The [node] is
|
||||
|
|
|
@ -1346,8 +1346,8 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
testingData: testingData,
|
||||
).analyze();
|
||||
|
||||
late UnitAnalysisResult fileResult;
|
||||
late Uint8List bytes;
|
||||
late CompilationUnit resolvedUnit;
|
||||
for (var unitResult in results) {
|
||||
var unitBytes =
|
||||
_serializeResolvedUnit(unitResult.unit, unitResult.errors);
|
||||
|
@ -1356,16 +1356,21 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
String unitKey = _getResolvedUnitKey(unitSignature);
|
||||
_byteStore.putGet(unitKey, unitBytes);
|
||||
if (unitResult.file == file) {
|
||||
fileResult = unitResult;
|
||||
bytes = unitBytes;
|
||||
resolvedUnit = unitResult.unit;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the result, full or partial.
|
||||
_logger.writeln('Computed new analysis result.');
|
||||
var result = _getAnalysisResultFromBytes(file, signature, bytes,
|
||||
content: withUnit ? file.content : null,
|
||||
resolvedUnit: withUnit ? resolvedUnit : null);
|
||||
var result = _getAnalysisResultFromBytes(
|
||||
file,
|
||||
signature,
|
||||
bytes,
|
||||
content: withUnit ? file.content : null,
|
||||
resolvedUnit: withUnit ? fileResult.unit : null,
|
||||
errors: fileResult.errors,
|
||||
);
|
||||
if (withUnit && _priorityFiles.contains(path)) {
|
||||
_priorityResults[path] = result.unitResult!;
|
||||
}
|
||||
|
@ -1588,10 +1593,15 @@ class AnalysisDriver implements AnalysisDriverGeneric {
|
|||
/// Load the [AnalysisResult] for the given [file] from the [bytes]. Set
|
||||
/// optional [content] and [resolvedUnit].
|
||||
AnalysisResult _getAnalysisResultFromBytes(
|
||||
FileState file, String signature, Uint8List bytes,
|
||||
{String? content, CompilationUnit? resolvedUnit}) {
|
||||
FileState file,
|
||||
String signature,
|
||||
Uint8List bytes, {
|
||||
String? content,
|
||||
CompilationUnit? resolvedUnit,
|
||||
List<AnalysisError>? errors,
|
||||
}) {
|
||||
var unit = AnalysisDriverResolvedUnit.fromBuffer(bytes);
|
||||
List<AnalysisError> errors = _getErrorsFromSerialized(file, unit.errors);
|
||||
errors ??= _getErrorsFromSerialized(file, unit.errors);
|
||||
_updateHasErrorOrWarningFlag(file, errors);
|
||||
var index = unit.index!;
|
||||
if (content != null && resolvedUnit != null) {
|
||||
|
|
|
@ -840,19 +840,24 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
errorToken,
|
||||
);
|
||||
} else if (error is NonExhaustiveError && reportNonExhaustive) {
|
||||
// TODO(paulberry): instead of using SimpleDartBuffer, use an
|
||||
// analyzer-specific class that implements DartBuffer and captures the
|
||||
// information needed for quick assists.
|
||||
var errorBuffer = SimpleDartBuffer();
|
||||
error.witness.toDart(errorBuffer, forCorrection: false);
|
||||
var correctionBuffer = SimpleDartBuffer();
|
||||
error.witness.toDart(correctionBuffer, forCorrection: true);
|
||||
var correctionTextBuffer = SimpleDartBuffer();
|
||||
var correctionDataBuffer = AnalyzerDartTemplateBuffer();
|
||||
error.witness.toDart(correctionTextBuffer, forCorrection: true);
|
||||
error.witness.toDart(correctionDataBuffer, forCorrection: true);
|
||||
_errorReporter.reportErrorForToken(
|
||||
isSwitchExpression
|
||||
? CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_EXPRESSION
|
||||
: CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT,
|
||||
switchKeyword,
|
||||
[scrutineeType, errorBuffer.toString(), correctionBuffer.toString()],
|
||||
[
|
||||
scrutineeType,
|
||||
errorBuffer.toString(),
|
||||
correctionTextBuffer.toString(),
|
||||
],
|
||||
[],
|
||||
correctionDataBuffer.isComplete ? correctionDataBuffer.parts : null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:_fe_analyzer_shared/src/exhaustiveness/dart_template_buffer.dart';
|
||||
import 'package:_fe_analyzer_shared/src/exhaustiveness/exhaustive.dart';
|
||||
import 'package:_fe_analyzer_shared/src/exhaustiveness/key.dart';
|
||||
import 'package:_fe_analyzer_shared/src/exhaustiveness/path.dart';
|
||||
|
@ -23,6 +24,64 @@ import 'package:analyzer/src/dart/element/type_system.dart';
|
|||
import 'package:analyzer/src/dart/resolver/variance.dart';
|
||||
import 'package:analyzer/src/generated/constant.dart';
|
||||
|
||||
/// The buffer that accumulates types and elements as is, so that they
|
||||
/// can be written latter into Dart code that considers imports. It also
|
||||
/// accumulates fragments of text, such as syntax `(`, or names of properties.
|
||||
class AnalyzerDartTemplateBuffer
|
||||
implements DartTemplateBuffer<DartObject, FieldElement, DartType> {
|
||||
final List<MissingPatternPart> parts = [];
|
||||
bool isComplete = true;
|
||||
|
||||
@override
|
||||
void write(String text) {
|
||||
parts.add(
|
||||
MissingPatternTextPart(text),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void writeBoolValue(bool value) {
|
||||
parts.add(
|
||||
MissingPatternTextPart('$value'),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void writeCoreType(String name) {
|
||||
parts.add(
|
||||
MissingPatternTextPart(name),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void writeEnumValue(FieldElement value, String name) {
|
||||
final enumElement = value.enclosingElement;
|
||||
if (enumElement is! EnumElement) {
|
||||
isComplete = false;
|
||||
return;
|
||||
}
|
||||
|
||||
parts.add(
|
||||
MissingPatternEnumValuePart(
|
||||
enumElement: enumElement,
|
||||
value: value,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void writeGeneralConstantValue(DartObject value, String name) {
|
||||
isComplete = false;
|
||||
}
|
||||
|
||||
@override
|
||||
void writeGeneralType(DartType type, String name) {
|
||||
parts.add(
|
||||
MissingPatternTypePart(type),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AnalyzerEnumOperations
|
||||
implements EnumOperations<DartType, EnumElement, FieldElement, DartObject> {
|
||||
const AnalyzerEnumOperations();
|
||||
|
@ -367,6 +426,41 @@ class ExhaustivenessDataForTesting {
|
|||
ExhaustivenessDataForTesting(this.objectFieldLookup);
|
||||
}
|
||||
|
||||
class MissingPatternEnumValuePart extends MissingPatternPart {
|
||||
final EnumElement enumElement;
|
||||
final FieldElement value;
|
||||
|
||||
MissingPatternEnumValuePart({
|
||||
required this.enumElement,
|
||||
required this.value,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() => value.name;
|
||||
}
|
||||
|
||||
abstract class MissingPatternPart {}
|
||||
|
||||
class MissingPatternTextPart extends MissingPatternPart {
|
||||
final String text;
|
||||
|
||||
MissingPatternTextPart(this.text);
|
||||
|
||||
@override
|
||||
String toString() => text;
|
||||
}
|
||||
|
||||
class MissingPatternTypePart extends MissingPatternPart {
|
||||
final DartType type;
|
||||
|
||||
MissingPatternTypePart(this.type);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return type.getDisplayString(withNullability: true);
|
||||
}
|
||||
}
|
||||
|
||||
class PatternConverter with SpaceCreator<DartPattern, DartType> {
|
||||
final FeatureSet featureSet;
|
||||
final AnalyzerExhaustivenessCache cache;
|
||||
|
|
|
@ -84,14 +84,24 @@ class CollectingReporter extends ErrorReporter {
|
|||
}
|
||||
|
||||
@override
|
||||
void reportErrorForNode(ErrorCode errorCode, AstNode node,
|
||||
[List<Object?>? arguments, List<DiagnosticMessage>? messages]) {
|
||||
void reportErrorForNode(
|
||||
ErrorCode errorCode,
|
||||
AstNode node, [
|
||||
List<Object?>? arguments,
|
||||
List<DiagnosticMessage>? messages,
|
||||
Object? data,
|
||||
]) {
|
||||
code = errorCode;
|
||||
}
|
||||
|
||||
@override
|
||||
void reportErrorForToken(ErrorCode errorCode, Token token,
|
||||
[List<Object?>? arguments, List<DiagnosticMessage>? messages]) {
|
||||
void reportErrorForToken(
|
||||
ErrorCode errorCode,
|
||||
Token token, [
|
||||
List<Object?>? arguments,
|
||||
List<DiagnosticMessage>? messages,
|
||||
Object? data,
|
||||
]) {
|
||||
code = errorCode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,9 @@ class MockAnalysisError implements AnalysisError {
|
|||
@override
|
||||
String? get correctionMessage => null;
|
||||
|
||||
@override
|
||||
Object? get data => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
DiagnosticMessage get problemMessage => DiagnosticMessageImpl(
|
||||
filePath: source.fullName,
|
||||
|
|
Loading…
Reference in a new issue