trphoenix
2018-11-29 25f4612acc6885d3f977c16252e2185b874b3394
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// 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:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:meta/meta.dart';
import 'package:source_gen/source_gen.dart';
 
import 'json_key_utils.dart';
import 'type_helper.dart';
import 'type_helper_ctx.dart';
import 'utils.dart';
 
abstract class HelperCore {
  final ClassElement element;
  final JsonSerializable config;
 
  HelperCore(this.element, this.config);
 
  Iterable<TypeHelper> get allTypeHelpers;
 
  void addMember(String memberContent);
 
  @protected
  String get targetClassReference =>
      '${element.name}${genericClassArgumentsImpl(false)}';
 
  @protected
  String nameAccess(FieldElement field) => jsonKeyFor(field).name;
 
  @protected
  String safeNameAccess(FieldElement field) =>
      escapeDartString(nameAccess(field));
 
  @protected
  String get prefix => '_\$${element.name}';
 
  /// Returns a [String] representing the type arguments that exist on
  /// [element].
  ///
  /// Returns the output of calling [genericClassArguments] with [element].
  @protected
  String genericClassArgumentsImpl(bool withConstraints) =>
      genericClassArguments(element, withConstraints);
 
  @protected
  JsonKey jsonKeyFor(FieldElement field) => jsonKeyForField(field, config);
 
  @protected
  TypeHelperContext getHelperContext(FieldElement field) =>
      typeHelperContext(this, field, jsonKeyFor(field));
}
 
InvalidGenerationSourceError createInvalidGenerationError(
    String targetMember, FieldElement field, UnsupportedTypeError e) {
  var message = 'Could not generate `$targetMember` code for `${field.name}`';
 
  var todo = 'Make sure all of the types are serializable.';
 
  if (e.type.isUndefined) {
    message = '$message because the type is undefined.';
    todo = "Check your imports. If you're trying to generate code for a "
        'Platform-provided type, you may have to specify a custom '
        '`$targetMember` in the associated `@JsonKey` annotation.';
  } else {
    if (field.type != e.type) {
      message = '$message because of type `${e.type}`';
    }
 
    message = '$message.\n${e.reason}';
  }
 
  return InvalidGenerationSourceError(message, todo: todo, element: field);
}
 
/// Returns a [String] representing the type arguments that exist on
/// [element].
///
/// If [withConstraints] is `null` or if [element] has no type arguments, an
/// empty [String] is returned.
///
/// If [withConstraints] is true, any type constraints that exist on [element]
/// are included.
///
/// For example, for class `class Sample<T as num, S>{...}`
///
/// For [withConstraints] = `false`:
///
/// ```
/// "<T, S>"
/// ```
///
/// For [withConstraints] = `true`:
///
/// ```
/// "<T as num, S>"
/// ```
String genericClassArguments(ClassElement element, bool withConstraints) {
  if (withConstraints == null || element.typeParameters.isEmpty) {
    return '';
  }
  final values = element.typeParameters
      .map((t) => withConstraints ? t.toString() : t.name)
      .join(', ');
  return '<$values>';
}
 
void warnUndefinedElements(Iterable<VariableElement> elements) {
  for (final element in elements.where((fe) => fe.type.isUndefined)) {
    final span = spanForElement(element);
    log.warning('''
This element has an undefined type. It may causes issues when generated code.
${span.start.toolString}
${span.highlight()}''');
  }
}