trphoenix
2018-11-19 524fe036f63de1056aab457781e0b7141a5b7adc
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
// 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';
// ignore: implementation_imports
import 'package:analyzer/src/dart/resolver/inheritance_manager.dart'
    show InheritanceManager;
import 'package:source_gen/source_gen.dart';
 
import 'helper_core.dart';
import 'utils.dart';
 
class _FieldSet implements Comparable<_FieldSet> {
  final FieldElement field;
  final FieldElement sortField;
 
  _FieldSet._(this.field, this.sortField)
      : assert(field.name == sortField.name);
 
  factory _FieldSet(FieldElement classField, FieldElement superField) {
    // At least one of these will != null, perhaps both.
    final fields = [classField, superField].where((fe) => fe != null).toList();
 
    // Prefer the class field over the inherited field when sorting.
    final sortField = fields.first;
 
    // Prefer the field that's annotated with `JsonKey`, if any.
    // If not, use the class field.
    final fieldHasJsonKey =
        fields.firstWhere(hasJsonKeyAnnotation, orElse: () => fields.first);
 
    return _FieldSet._(fieldHasJsonKey, sortField);
  }
 
  @override
  int compareTo(_FieldSet other) => _sortByLocation(sortField, other.sortField);
 
  static int _sortByLocation(FieldElement a, FieldElement b) {
    final checkerA = TypeChecker.fromStatic(a.enclosingElement.type);
 
    if (!checkerA.isExactly(b.enclosingElement)) {
      // in this case, you want to prioritize the enclosingElement that is more
      // "super".
 
      if (checkerA.isSuperOf(b.enclosingElement)) {
        return -1;
      }
 
      final checkerB = TypeChecker.fromStatic(b.enclosingElement.type);
 
      if (checkerB.isSuperOf(a.enclosingElement)) {
        return 1;
      }
    }
 
    /// Returns the offset of given field/property in its source file – with a
    /// preference for the getter if it's defined.
    int _offsetFor(FieldElement e) {
      if (e.getter != null && e.getter.nameOffset != e.nameOffset) {
        assert(e.nameOffset == -1);
        return e.getter.nameOffset;
      }
      return e.nameOffset;
    }
 
    return _offsetFor(a).compareTo(_offsetFor(b));
  }
}
 
/// Returns a [Set] of all instance [FieldElement] items for [element] and
/// super classes, sorted first by their location in the inheritance hierarchy
/// (super first) and then by their location in the source file.
Iterable<FieldElement> createSortedFieldSet(ClassElement element) {
  // Get all of the fields that need to be assigned
  // TODO: support overriding the field set with an annotation option
  final elementInstanceFields = Map.fromEntries(
      element.fields.where((e) => !e.isStatic).map((e) => MapEntry(e.name, e)));
 
  final inheritedFields = <String, FieldElement>{};
  final manager = InheritanceManager(element.library);
 
  // ignore: deprecated_member_use
  for (final v in manager.getMembersInheritedFromClasses(element).values) {
    assert(v is! FieldElement);
    if (_dartCoreObjectChecker.isExactly(v.enclosingElement)) {
      continue;
    }
 
    if (v is PropertyAccessorElement && v.isGetter) {
      assert(v.variable is FieldElement);
      final variable = v.variable as FieldElement;
      assert(!inheritedFields.containsKey(variable.name));
      inheritedFields[variable.name] = variable;
    }
  }
 
  // Get the list of all fields for `element`
  final allFields =
      elementInstanceFields.keys.toSet().union(inheritedFields.keys.toSet());
 
  final fields = allFields
      .map((e) => _FieldSet(elementInstanceFields[e], inheritedFields[e]))
      .toList();
 
  // Sort the fields using the `compare` implementation in _FieldSet
  fields.sort();
 
  final fieldList = fields.map((fs) => fs.field).toList();
  warnUndefinedElements(fieldList);
  return fieldList;
}
 
const _dartCoreObjectChecker = TypeChecker.fromRuntime(Object);