update json macro and macro code, to handle omitted types better and not crash the analyzer Change-Id: I2b30568dd4163b0032624f1fd0db6d6a6246f16c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/365960 Auto-Submit: Jake Macdonald <jakemac@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/json/lib/json.dart b/pkg/json/lib/json.dart index b3f9aff..b96fb2f 100644 --- a/pkg/json/lib/json.dart +++ b/pkg/json/lib/json.dart
@@ -310,19 +310,14 @@ /// Returns a [Code] object which is an expression that converts a JSON map /// (referenced by [jsonReference]) into an instance of type [type]. Future<Code> _convertTypeFromJson( - TypeAnnotation type, + TypeAnnotation rawType, Code jsonReference, DefinitionBuilder builder, _SharedIntrospectionData introspectionData) async { - if (type is! NamedTypeAnnotation) { - builder.report(Diagnostic( - DiagnosticMessage( - 'Only fields with named types are allowed on serializable ' - 'classes', - target: type.asDiagnosticTarget), - Severity.error)); + final type = _checkNamedType(rawType, builder); + if (type == null) { return RawCode.fromString( - "throw 'Unable to deserialize type ${type.code.debugString}'"); + "throw 'Unable to deserialize type ${rawType.code.debugString}'"); } // Follow type aliases until we reach an actual named type. @@ -407,6 +402,28 @@ ]); } + /// Returns [type] as a [NamedTypeAnnotation] if it is one, otherwise returns + /// `null` and emits relevant error diagnostics. + NamedTypeAnnotation? _checkNamedType(TypeAnnotation type, Builder builder) { + if (type is NamedTypeAnnotation) return type; + if (type is OmittedTypeAnnotation) { + builder.report(Diagnostic( + DiagnosticMessage( + 'Only fields with explicit types are allowed on serializable ' + 'classes, please add a type.', + target: type.asDiagnosticTarget), + Severity.error)); + } else { + builder.report(Diagnostic( + DiagnosticMessage( + 'Only fields with named types are allowed on serializable ' + 'classes.', + target: type.asDiagnosticTarget), + Severity.error)); + } + return null; + } + /// Checks that [method] is a valid `toJson` method, and throws a /// [DiagnosticException] if not. Future<bool> _checkValidToJson( @@ -431,19 +448,14 @@ /// Returns a [Code] object which is an expression that converts an instance /// of type [type] (referenced by [valueReference]) into a JSON map. Future<Code> _convertTypeToJson( - TypeAnnotation type, + TypeAnnotation rawType, Code valueReference, DefinitionBuilder builder, _SharedIntrospectionData introspectionData) async { - if (type is! NamedTypeAnnotation) { - builder.report(Diagnostic( - DiagnosticMessage( - 'Only fields with named types are allowed on serializable ' - 'classes', - target: type.asDiagnosticTarget), - Severity.error)); + final type = _checkNamedType(rawType, builder); + if (type == null) { return RawCode.fromString( - "throw 'Unable to serialize type ${type.code.debugString}'"); + "throw 'Unable to serialize type ${rawType.code.debugString}'"); } // Follow type aliases until we reach an actual named type. @@ -651,6 +663,8 @@ part._writeDebugString(buffer); case Identifier(): buffer.write(part.name); + case OmittedTypeAnnotation(): + buffer.write('<omitted>'); default: buffer.write(part); }