mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:39:49 +00:00
Record superInterface and use it for OverrideVerifier.
R=brianwilkerson@google.com Change-Id: Ib6fe2b14affc8f8d00c32f123a4b587ae6d8fb56 Reviewed-on: https://dart-review.googlesource.com/77521 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
158290349a
commit
b8c831592a
|
@ -39,10 +39,11 @@ import 'package:front_end/src/dependency_walker.dart';
|
|||
* Analyzer of a single library.
|
||||
*/
|
||||
class LibraryAnalyzer {
|
||||
final AnalysisOptions _analysisOptions;
|
||||
final AnalysisOptionsImpl _analysisOptions;
|
||||
final DeclaredVariables _declaredVariables;
|
||||
final SourceFactory _sourceFactory;
|
||||
final FileState _library;
|
||||
final InheritanceManager2 _inheritance;
|
||||
|
||||
final bool Function(Uri) _isLibraryUri;
|
||||
final AnalysisContextImpl _context;
|
||||
|
@ -69,7 +70,8 @@ class LibraryAnalyzer {
|
|||
this._context,
|
||||
this._resynthesizer,
|
||||
this._library)
|
||||
: _typeProvider = _context.typeProvider;
|
||||
: _inheritance = new InheritanceManager2(_context.typeSystem),
|
||||
_typeProvider = _context.typeProvider;
|
||||
|
||||
/**
|
||||
* Compute analysis results for all units of the library.
|
||||
|
@ -210,15 +212,12 @@ class LibraryAnalyzer {
|
|||
unit.accept(new Dart2JSVerifier(errorReporter));
|
||||
}
|
||||
|
||||
InheritanceManager inheritanceManager = new InheritanceManager(
|
||||
_libraryElement,
|
||||
includeAbstractFromSuperclasses: true);
|
||||
|
||||
unit.accept(new BestPracticesVerifier(
|
||||
errorReporter, _typeProvider, _libraryElement, inheritanceManager,
|
||||
errorReporter, _typeProvider, _libraryElement,
|
||||
typeSystem: _context.typeSystem));
|
||||
|
||||
unit.accept(new OverrideVerifier(errorReporter, inheritanceManager));
|
||||
unit.accept(
|
||||
new OverrideVerifier(_inheritance, _libraryElement, errorReporter));
|
||||
|
||||
new ToDoFinder(errorReporter).findIn(unit);
|
||||
|
||||
|
@ -296,14 +295,12 @@ class LibraryAnalyzer {
|
|||
|
||||
RecordingErrorListener errorListener = _getErrorListener(file);
|
||||
|
||||
AnalysisOptionsImpl options = _analysisOptions as AnalysisOptionsImpl;
|
||||
var typeSystem = new StrongTypeSystemImpl(_typeProvider,
|
||||
implicitCasts: options.implicitCasts,
|
||||
declarationCasts: options.declarationCasts,
|
||||
nonnullableTypes: options.nonnullableTypes);
|
||||
|
||||
CodeChecker checker =
|
||||
new CodeChecker(_typeProvider, typeSystem, errorListener, options);
|
||||
CodeChecker checker = new CodeChecker(
|
||||
_typeProvider,
|
||||
_context.typeSystem,
|
||||
errorListener,
|
||||
_analysisOptions,
|
||||
);
|
||||
checker.visitCompilationUnit(unit);
|
||||
|
||||
ErrorReporter errorReporter = _getErrorReporter(file);
|
||||
|
@ -321,9 +318,8 @@ class LibraryAnalyzer {
|
|||
//
|
||||
// Compute inheritance and override errors.
|
||||
//
|
||||
var inheritanceManager2 = new InheritanceManager2(typeSystem);
|
||||
var inheritanceOverrideVerifier = new InheritanceOverrideVerifier(
|
||||
typeSystem, inheritanceManager2, errorReporter);
|
||||
_context.typeSystem, _inheritance, errorReporter);
|
||||
inheritanceOverrideVerifier.verifyUnit(unit);
|
||||
|
||||
//
|
||||
|
@ -334,7 +330,7 @@ class LibraryAnalyzer {
|
|||
_libraryElement,
|
||||
_typeProvider,
|
||||
new InheritanceManager(_libraryElement),
|
||||
inheritanceManager2,
|
||||
_inheritance,
|
||||
_analysisOptions.enableSuperMixins);
|
||||
unit.accept(errorVerifier);
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ class InheritanceManager2 {
|
|||
/// members, not necessary accessible in all libraries.
|
||||
Interface getInterface(InterfaceType type) {
|
||||
if (type == null) {
|
||||
return const Interface._(const {}, const [{}], const []);
|
||||
return const Interface._(const {}, const {}, const [{}], const []);
|
||||
}
|
||||
|
||||
var result = _interfaces[type];
|
||||
|
@ -55,10 +55,16 @@ class InheritanceManager2 {
|
|||
return result;
|
||||
}
|
||||
|
||||
_interfaces[type] = const Interface._(const {}, const [{}], const []);
|
||||
_interfaces[type] = const Interface._(
|
||||
const {},
|
||||
const {},
|
||||
const [{}],
|
||||
const [],
|
||||
);
|
||||
Map<Name, FunctionType> superInterface = {};
|
||||
Map<Name, FunctionType> map = {};
|
||||
List<Map<Name, FunctionType>> supers = [];
|
||||
List<Conflict> conflicts = null;
|
||||
List<Map<Name, FunctionType>> superImplemented = [];
|
||||
|
||||
// If a class declaration has a member declaration, the signature of that
|
||||
// member declaration becomes the signature in the interface.
|
||||
|
@ -73,8 +79,12 @@ class InheritanceManager2 {
|
|||
// `mixin M on S1, S2 {}` can call using `super` any instance member
|
||||
// from its superclass constraints, whether it is abstract or concrete.
|
||||
Map<Name, FunctionType> mixinSuperClass = {};
|
||||
_findMostSpecificFromNamedCandidates(mixinSuperClass, namedCandidates);
|
||||
supers.add(mixinSuperClass);
|
||||
_findMostSpecificFromNamedCandidates(
|
||||
namedCandidates,
|
||||
superInterface,
|
||||
mixinSuperClass,
|
||||
);
|
||||
superImplemented.add(mixinSuperClass);
|
||||
} else {
|
||||
Map<Name, FunctionType> implemented;
|
||||
|
||||
|
@ -82,7 +92,7 @@ class InheritanceManager2 {
|
|||
_addCandidates(namedCandidates, type.superclass);
|
||||
|
||||
implemented = _getImplemented(type.superclass);
|
||||
supers.add(implemented);
|
||||
superImplemented.add(implemented);
|
||||
}
|
||||
|
||||
for (var mixin in type.mixins) {
|
||||
|
@ -92,7 +102,7 @@ class InheritanceManager2 {
|
|||
implemented = <Name, FunctionType>{}
|
||||
..addAll(implemented)
|
||||
..addAll(implementedInMixin);
|
||||
supers.add(implemented);
|
||||
superImplemented.add(implemented);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,9 +116,18 @@ class InheritanceManager2 {
|
|||
// super-interfaces that is a valid override of all the other
|
||||
// super-interface signatures with the same name. That "most specific"
|
||||
// signature becomes the signature of the class's interface.
|
||||
conflicts = _findMostSpecificFromNamedCandidates(map, namedCandidates);
|
||||
conflicts = _findMostSpecificFromNamedCandidates(
|
||||
namedCandidates,
|
||||
superInterface,
|
||||
map,
|
||||
);
|
||||
|
||||
var interface = new Interface._(map, supers, conflicts ?? const []);
|
||||
var interface = new Interface._(
|
||||
map,
|
||||
superInterface,
|
||||
superImplemented,
|
||||
conflicts ?? const [],
|
||||
);
|
||||
_interfaces[type] = interface;
|
||||
return interface;
|
||||
}
|
||||
|
@ -132,7 +151,7 @@ class InheritanceManager2 {
|
|||
bool forSuper: false,
|
||||
}) {
|
||||
if (forSuper) {
|
||||
var supers = getInterface(type)._supers;
|
||||
var supers = getInterface(type)._superImplemented;
|
||||
if (forMixinIndex >= 0) {
|
||||
return supers[forMixinIndex][name];
|
||||
}
|
||||
|
@ -218,33 +237,38 @@ class InheritanceManager2 {
|
|||
}
|
||||
|
||||
/// The given [namedCandidates] maps names to candidates from direct
|
||||
/// superinterfaces. Find the most specific signature, and put it into the
|
||||
/// [map], if there is no one yet (from the class itself). If there is no
|
||||
/// such single most specific signature (i.e. no valid override), then add a
|
||||
/// new conflict description.
|
||||
/// superinterfaces. Find the most specific signature, and put it into both
|
||||
/// [superInterface]. If the class itself does not define the name, put it
|
||||
/// also into the class interface [map]. If there is no such single most
|
||||
/// specific signature (i.e. no valid override), then add a new conflict
|
||||
/// description.
|
||||
List<Conflict> _findMostSpecificFromNamedCandidates(
|
||||
Map<Name, FunctionType> map,
|
||||
Map<Name, List<FunctionType>> namedCandidates) {
|
||||
Map<Name, List<FunctionType>> namedCandidates,
|
||||
Map<Name, FunctionType> superInterface,
|
||||
Map<Name, FunctionType> map,
|
||||
) {
|
||||
List<Conflict> conflicts = null;
|
||||
|
||||
for (var name in namedCandidates.keys) {
|
||||
if (map.containsKey(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var isDefinedByClass = map.containsKey(name);
|
||||
var candidates = namedCandidates[name];
|
||||
|
||||
// If just one candidate, it is always valid.
|
||||
if (candidates.length == 1) {
|
||||
map[name] = candidates[0];
|
||||
superInterface[name] = candidates[0];
|
||||
if (!isDefinedByClass) {
|
||||
map[name] = candidates[0];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for a getter/method conflict.
|
||||
var conflict = _checkForGetterMethodConflict(name, candidates);
|
||||
if (conflict != null) {
|
||||
conflicts ??= <Conflict>[];
|
||||
conflicts.add(conflict);
|
||||
if (!isDefinedByClass) {
|
||||
var conflict = _checkForGetterMethodConflict(name, candidates);
|
||||
if (conflict != null) {
|
||||
conflicts ??= <Conflict>[];
|
||||
conflicts.add(conflict);
|
||||
}
|
||||
}
|
||||
|
||||
FunctionType validOverride;
|
||||
|
@ -263,8 +287,11 @@ class InheritanceManager2 {
|
|||
}
|
||||
|
||||
if (validOverride != null) {
|
||||
map[name] = validOverride;
|
||||
} else {
|
||||
superInterface[name] = validOverride;
|
||||
if (!isDefinedByClass) {
|
||||
map[name] = validOverride;
|
||||
}
|
||||
} else if (!isDefinedByClass) {
|
||||
conflicts ??= <Conflict>[];
|
||||
conflicts.add(new Conflict(name, candidates));
|
||||
}
|
||||
|
@ -356,18 +383,26 @@ class Interface {
|
|||
/// The map of names to their signature in the interface.
|
||||
final Map<Name, FunctionType> map;
|
||||
|
||||
/// The map of names to their signature in superinterfaces.
|
||||
final Map<Name, FunctionType> superInterface;
|
||||
|
||||
/// Each item of this list maps names to their concrete implementations.
|
||||
/// The first item of the list is the nominal superclass, next the nominal
|
||||
/// superclass plus the first mixin, etc. So, for the class like
|
||||
/// `class C extends S with M1, M2`, we get `[S, S&M1, S&M1&M2]`.
|
||||
final List<Map<Name, FunctionType>> _supers;
|
||||
final List<Map<Name, FunctionType>> _superImplemented;
|
||||
|
||||
/// The list of conflicts between superinterfaces - the nominal superclass,
|
||||
/// mixins, and interfaces. Does not include conflicts with the declared
|
||||
/// members of the class.
|
||||
final List<Conflict> conflicts;
|
||||
|
||||
const Interface._(this.map, this._supers, this.conflicts);
|
||||
const Interface._(
|
||||
this.map,
|
||||
this.superInterface,
|
||||
this._superImplemented,
|
||||
this.conflicts,
|
||||
);
|
||||
}
|
||||
|
||||
/// A public name, or a private name qualified by a library URI.
|
||||
|
|
|
@ -19,6 +19,7 @@ import 'package:analyzer/src/dart/ast/ast_factory.dart';
|
|||
import 'package:analyzer/src/dart/ast/token.dart';
|
||||
import 'package:analyzer/src/dart/ast/utilities.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/inheritance_manager2.dart';
|
||||
import 'package:analyzer/src/dart/element/member.dart' show ConstructorMember;
|
||||
import 'package:analyzer/src/dart/element/type.dart';
|
||||
import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
|
||||
|
@ -276,14 +277,11 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
|
|||
/// The current library
|
||||
LibraryElement _currentLibrary;
|
||||
|
||||
/// The inheritance manager used to find overridden methods.
|
||||
InheritanceManager _manager;
|
||||
|
||||
/// Create a new instance of the [BestPracticesVerifier].
|
||||
///
|
||||
/// @param errorReporter the error reporter
|
||||
BestPracticesVerifier(this._errorReporter, TypeProvider typeProvider,
|
||||
this._currentLibrary, this._manager,
|
||||
BestPracticesVerifier(
|
||||
this._errorReporter, TypeProvider typeProvider, this._currentLibrary,
|
||||
{TypeSystem typeSystem})
|
||||
: _nullType = typeProvider.nullType,
|
||||
_futureNullType = typeProvider.futureNullType,
|
||||
|
@ -3895,28 +3893,39 @@ class InstanceFieldResolverVisitor extends ResolverVisitor {
|
|||
/// compilation unit to verify that if they have an override annotation it is
|
||||
/// being used correctly.
|
||||
class OverrideVerifier extends RecursiveAstVisitor {
|
||||
/// The inheritance manager used to find overridden methods.
|
||||
final InheritanceManager2 _inheritance;
|
||||
|
||||
/// The library being verified.
|
||||
final LibraryElement _library;
|
||||
|
||||
/// The error reporter used to report errors.
|
||||
final ErrorReporter _errorReporter;
|
||||
|
||||
/// The inheritance manager used to find overridden methods.
|
||||
final InheritanceManager _manager;
|
||||
/// The interface of the current class.
|
||||
Interface _currentInterface;
|
||||
|
||||
/// Initialize a newly created verifier to look for inappropriate uses of the
|
||||
/// override annotation.
|
||||
///
|
||||
/// @param errorReporter the error reporter used to report errors
|
||||
/// @param manager the inheritance manager used to find overridden methods
|
||||
OverrideVerifier(this._errorReporter, this._manager);
|
||||
OverrideVerifier(this._inheritance, this._library, this._errorReporter);
|
||||
|
||||
@override
|
||||
visitClassDeclaration(ClassDeclaration node) {
|
||||
_currentInterface = _inheritance.getInterface(node.declaredElement.type);
|
||||
super.visitClassDeclaration(node);
|
||||
_currentInterface = null;
|
||||
}
|
||||
|
||||
@override
|
||||
visitFieldDeclaration(FieldDeclaration node) {
|
||||
for (VariableDeclaration field in node.fields.variables) {
|
||||
VariableElement fieldElement = field.declaredElement;
|
||||
if (fieldElement is FieldElement && _isOverride(fieldElement)) {
|
||||
PropertyAccessorElement getter = fieldElement.getter;
|
||||
PropertyAccessorElement setter = fieldElement.setter;
|
||||
if (!(getter != null && _getOverriddenMember(getter) != null ||
|
||||
setter != null && _getOverriddenMember(setter) != null)) {
|
||||
FieldElement fieldElement = field.declaredElement;
|
||||
if (fieldElement.hasOverride) {
|
||||
if (!_isOverride(fieldElement.getter) &&
|
||||
!_isOverride(fieldElement.setter)) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD, field.name);
|
||||
}
|
||||
|
@ -3927,8 +3936,8 @@ class OverrideVerifier extends RecursiveAstVisitor {
|
|||
@override
|
||||
visitMethodDeclaration(MethodDeclaration node) {
|
||||
ExecutableElement element = node.declaredElement;
|
||||
if (_isOverride(element)) {
|
||||
if (_getOverriddenMember(element) == null) {
|
||||
if (element.hasOverride) {
|
||||
if (!_isOverride(element)) {
|
||||
if (element is MethodElement) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD, node.name);
|
||||
|
@ -3945,30 +3954,14 @@ class OverrideVerifier extends RecursiveAstVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return the member that overrides the given member.
|
||||
///
|
||||
/// @param member the member that overrides the returned member
|
||||
/// @return the member that overrides the given member
|
||||
ExecutableElement _getOverriddenMember(ExecutableElement member) {
|
||||
LibraryElement library = member.library;
|
||||
if (library == null) {
|
||||
return null;
|
||||
/// Return `true` if the [member] overrides a member from the superinterface.
|
||||
bool _isOverride(ExecutableElement member) {
|
||||
if (member == null) {
|
||||
return false;
|
||||
}
|
||||
ClassElement classElement =
|
||||
member.getAncestor((element) => element is ClassElement);
|
||||
if (classElement == null) {
|
||||
return null;
|
||||
}
|
||||
return _manager.lookupInheritance(classElement, member.name);
|
||||
var name = new Name(_library.source.uri, member.name);
|
||||
return _currentInterface.superInterface.containsKey(name);
|
||||
}
|
||||
|
||||
/// Return `true` if the given element has an override annotation associated
|
||||
/// with it.
|
||||
///
|
||||
/// @param element the element being tested
|
||||
/// @return `true` if the element has an override annotation associated with
|
||||
/// it
|
||||
bool _isOverride(Element element) => element != null && element.hasOverride;
|
||||
}
|
||||
|
||||
/// An AST visitor that is used to resolve the some of the nodes within a single
|
||||
|
|
|
@ -2855,15 +2855,15 @@ class GenerateHintsTask extends SourceBasedAnalysisTask {
|
|||
unit.accept(new Dart2JSVerifier(errorReporter));
|
||||
}
|
||||
// Dart best practices.
|
||||
InheritanceManager inheritanceManager = new InheritanceManager(
|
||||
libraryElement,
|
||||
includeAbstractFromSuperclasses: true);
|
||||
InheritanceManager2 inheritanceManager2 =
|
||||
new InheritanceManager2(libraryElement.context.typeSystem);
|
||||
TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
|
||||
|
||||
unit.accept(new BestPracticesVerifier(
|
||||
errorReporter, typeProvider, libraryElement, inheritanceManager,
|
||||
errorReporter, typeProvider, libraryElement,
|
||||
typeSystem: typeSystem));
|
||||
unit.accept(new OverrideVerifier(errorReporter, inheritanceManager));
|
||||
unit.accept(new OverrideVerifier(
|
||||
inheritanceManager2, libraryElement, errorReporter));
|
||||
// Find to-do comments.
|
||||
new ToDoFinder(errorReporter).findIn(unit);
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue