blob: cfc5abf0097cd99f477fba672bbaab17e3c39b27 [file] [log] [blame]
// Copyright (c) 2017, Google Inc. 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 'dart:collection';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:built_collection/built_collection.dart';
/// Gets fields, including from interfaces. Fields from interfaces are only
/// returned if they are not also implemented by a mixin.
///
/// If a field is overridden then just the closest (overriding) field is
/// returned.
BuiltList<FieldElement> collectFields(ClassElement element) =>
collectFieldsForType(element.type);
/// Gets fields, including from interfaces. Fields from interfaces are only
/// returned if they are not also implemented by a mixin.
///
/// If a field is overridden then just the closest (overriding) field is
/// returned.
BuiltList<FieldElement> collectFieldsForType(InterfaceType type) {
var fields = <FieldElement>[];
// Add fields from this class before interfaces, so they're added to the set
// first below. Re-added fields from interfaces are ignored.
fields.addAll(_fieldElementsForType(type));
Set<InterfaceType>.from(type.interfaces)
..addAll(type.mixins)
..forEach((interface) => fields.addAll(collectFieldsForType(interface)));
// Overridden fields have multiple declarations, so deduplicate by adding
// to a set that compares on field name.
var fieldSet = LinkedHashSet<FieldElement>(
equals: (a, b) => a.displayName == b.displayName,
hashCode: (a) => a.displayName.hashCode);
fieldSet.addAll(fields);
// Filter to fields that are not implemented by a mixin.
return BuiltList<FieldElement>.build((b) => b
..addAll(fieldSet)
..where((field) =>
type.lookUpInheritedGetter(field.name, thisType: false)?.isAbstract ??
true));
}
BuiltList<FieldElement> _fieldElementsForType(InterfaceType type) {
var result = ListBuilder<FieldElement>();
for (var accessor in type.accessors) {
if (accessor.isSetter) continue;
result.add(accessor.variable as FieldElement);
}
return result.build();
}