| Index: pkg/analyzer/lib/src/generated/error_verifier.dart
|
| diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
|
| index 30a50cc3a9ffbc687a631c0ef2fb0959ad901305..0d6ecf83ff5ee7a4c3b5e83705b724de0a531009 100644
|
| --- a/pkg/analyzer/lib/src/generated/error_verifier.dart
|
| +++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
|
| @@ -4989,104 +4989,19 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
| } else if (_enclosingClass.hasNoSuchMethod) {
|
| return;
|
| }
|
| - //
|
| - // Store in local sets the set of all method and accessor names
|
| - //
|
| - HashSet<ExecutableElement> missingOverrides =
|
| - new HashSet<ExecutableElement>();
|
| - //
|
| - // Loop through the set of all executable elements declared in the implicit
|
| - // interface.
|
| - //
|
| - Map<String, ExecutableElement> membersInheritedFromInterfaces =
|
| - _inheritanceManager.getMembersInheritedFromInterfaces(_enclosingClass);
|
| - Map<String, ExecutableElement> membersInheritedFromSuperclasses =
|
| - _inheritanceManager.getMembersInheritedFromClasses(_enclosingClass);
|
| - for (String memberName in membersInheritedFromInterfaces.keys) {
|
| - ExecutableElement executableElt =
|
| - membersInheritedFromInterfaces[memberName];
|
| - if (memberName == null) {
|
| - break;
|
| - }
|
| - // If the element is not synthetic and can be determined to be defined in
|
| - // Object, skip it.
|
| - if (executableElt.enclosingElement != null &&
|
| - (executableElt.enclosingElement as ClassElement).type.isObject) {
|
| - continue;
|
| - }
|
| - // Check to see if some element is in local enclosing class that matches
|
| - // the name of the required member.
|
| - if (_isMemberInClassOrMixin(executableElt, _enclosingClass)) {
|
| - // We do not have to verify that this implementation of the found method
|
| - // matches the required function type: the set of
|
| - // StaticWarningCode.INVALID_METHOD_OVERRIDE_* warnings break out the
|
| - // different specific situations.
|
| - continue;
|
| - }
|
| - // First check to see if this element was declared in the superclass
|
| - // chain, in which case there is already a concrete implementation.
|
| - ExecutableElement elt = membersInheritedFromSuperclasses[memberName];
|
| - // Check to see if an element was found in the superclass chain with the
|
| - // correct name.
|
| - if (elt != null) {
|
| - // Reference the types, if any are null then continue.
|
| - InterfaceType enclosingType = _enclosingClass.type;
|
| - FunctionType concreteType = elt.type;
|
| - FunctionType requiredMemberType = executableElt.type;
|
| - if (enclosingType == null ||
|
| - concreteType == null ||
|
| - requiredMemberType == null) {
|
| - continue;
|
| - }
|
| - // Some element was found in the superclass chain that matches the name
|
| - // of the required member.
|
| - // If it is not abstract and it is the correct one (types match- the
|
| - // version of this method that we have has the correct number of
|
| - // parameters, etc), then this class has a valid implementation of this
|
| - // method, so skip it.
|
| - if ((elt is MethodElement && !elt.isAbstract) ||
|
| - (elt is PropertyAccessorElement && !elt.isAbstract)) {
|
| - // Since we are comparing two function types, we need to do the
|
| - // appropriate type substitutions first ().
|
| - FunctionType foundConcreteFT = _inheritanceManager
|
| - .substituteTypeArgumentsInMemberFromInheritance(
|
| - concreteType, memberName, enclosingType);
|
| - FunctionType requiredMemberFT = _inheritanceManager
|
| - .substituteTypeArgumentsInMemberFromInheritance(
|
| - requiredMemberType, memberName, enclosingType);
|
| - foundConcreteFT = _typeSystem.functionTypeToConcreteType(
|
| - _typeProvider, foundConcreteFT);
|
| - requiredMemberFT = _typeSystem.functionTypeToConcreteType(
|
| - _typeProvider, requiredMemberFT);
|
|
|
| - // Strong mode does override checking for types in CodeChecker, so
|
| - // we can skip it here. Doing it here leads to unnecessary duplicate
|
| - // error messages in subclasses that inherit from one that has an
|
| - // override error.
|
| - //
|
| - // See: https://github.com/dart-lang/sdk/issues/25232
|
| - if (_options.strongMode ||
|
| - _typeSystem.isSubtypeOf(foundConcreteFT, requiredMemberFT)) {
|
| - continue;
|
| - }
|
| - }
|
| - }
|
| - // The not qualifying concrete executable element was found, add it to the
|
| - // list.
|
| - missingOverrides.add(executableElt);
|
| - }
|
| - // Now that we have the set of missing overrides, generate a warning on this
|
| - // class.
|
| - int missingOverridesSize = missingOverrides.length;
|
| - if (missingOverridesSize == 0) {
|
| + Set<ExecutableElement> missingOverrides = computeMissingOverrides(
|
| + _options.strongMode,
|
| + _typeProvider,
|
| + _typeSystem,
|
| + _inheritanceManager,
|
| + _enclosingClass);
|
| + if (missingOverrides.isEmpty) {
|
| return;
|
| }
|
| - List<ExecutableElement> missingOverridesArray =
|
| - new List.from(missingOverrides);
|
| - List<String> stringMembersArrayListSet = new List<String>();
|
| - for (int i = 0; i < missingOverridesArray.length; i++) {
|
| - String newStrMember;
|
| - ExecutableElement element = missingOverridesArray[i];
|
| +
|
| + List<String> missingOverrideNames = <String>[];
|
| + for (ExecutableElement element in missingOverrides) {
|
| Element enclosingElement = element.enclosingElement;
|
| String prefix = StringUtilities.EMPTY;
|
| if (element is PropertyAccessorElement) {
|
| @@ -5098,60 +5013,57 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
| // "setter "
|
| }
|
| }
|
| + String newStrMember;
|
| if (enclosingElement != null) {
|
| newStrMember =
|
| "$prefix'${enclosingElement.displayName}.${element.displayName}'";
|
| } else {
|
| newStrMember = "$prefix'${element.displayName}'";
|
| }
|
| - stringMembersArrayListSet.add(newStrMember);
|
| + missingOverrideNames.add(newStrMember);
|
| }
|
| - List<String> stringMembersArray = new List.from(stringMembersArrayListSet);
|
| - stringMembersArray.sort();
|
| - AnalysisErrorWithProperties analysisError;
|
| - if (stringMembersArray.length == 1) {
|
| - analysisError = _errorReporter.newErrorWithProperties(
|
| + missingOverrideNames.sort();
|
| +
|
| + if (missingOverrideNames.length == 1) {
|
| + _errorReporter.reportErrorForNode(
|
| StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE,
|
| classNameNode,
|
| - [stringMembersArray[0]]);
|
| - } else if (stringMembersArray.length == 2) {
|
| - analysisError = _errorReporter.newErrorWithProperties(
|
| + [missingOverrideNames[0]]);
|
| + } else if (missingOverrideNames.length == 2) {
|
| + _errorReporter.reportErrorForNode(
|
| StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO,
|
| classNameNode,
|
| - [stringMembersArray[0], stringMembersArray[1]]);
|
| - } else if (stringMembersArray.length == 3) {
|
| - analysisError = _errorReporter.newErrorWithProperties(
|
| + [missingOverrideNames[0], missingOverrideNames[1]]);
|
| + } else if (missingOverrideNames.length == 3) {
|
| + _errorReporter.reportErrorForNode(
|
| StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE,
|
| classNameNode, [
|
| - stringMembersArray[0],
|
| - stringMembersArray[1],
|
| - stringMembersArray[2]
|
| + missingOverrideNames[0],
|
| + missingOverrideNames[1],
|
| + missingOverrideNames[2]
|
| ]);
|
| - } else if (stringMembersArray.length == 4) {
|
| - analysisError = _errorReporter.newErrorWithProperties(
|
| + } else if (missingOverrideNames.length == 4) {
|
| + _errorReporter.reportErrorForNode(
|
| StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR,
|
| classNameNode, [
|
| - stringMembersArray[0],
|
| - stringMembersArray[1],
|
| - stringMembersArray[2],
|
| - stringMembersArray[3]
|
| + missingOverrideNames[0],
|
| + missingOverrideNames[1],
|
| + missingOverrideNames[2],
|
| + missingOverrideNames[3]
|
| ]);
|
| } else {
|
| - analysisError = _errorReporter.newErrorWithProperties(
|
| + _errorReporter.reportErrorForNode(
|
| StaticWarningCode
|
| .NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS,
|
| classNameNode,
|
| [
|
| - stringMembersArray[0],
|
| - stringMembersArray[1],
|
| - stringMembersArray[2],
|
| - stringMembersArray[3],
|
| - stringMembersArray.length - 4
|
| + missingOverrideNames[0],
|
| + missingOverrideNames[1],
|
| + missingOverrideNames[2],
|
| + missingOverrideNames[3],
|
| + missingOverrideNames.length - 4
|
| ]);
|
| }
|
| - analysisError.setProperty(
|
| - ErrorProperty.UNIMPLEMENTED_METHODS, missingOverridesArray);
|
| - _errorReporter.reportError(analysisError);
|
| }
|
|
|
| /**
|
| @@ -6537,57 +6449,6 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
| }
|
|
|
| /**
|
| - * Return `true` iff the given [classElement] has a concrete method, getter or
|
| - * setter that matches the name of the given [executableElement] in either the
|
| - * class itself, or one of its' mixins.
|
| - *
|
| - * By "match", only the name of the member is tested to match, it does not
|
| - * have to equal or be a subtype of the given executable element, this is due
|
| - * to the specific use where this method is used in
|
| - * [_checkForNonAbstractClassInheritsAbstractMember].
|
| - */
|
| - bool _isMemberInClassOrMixin(
|
| - ExecutableElement executableElement, ClassElement classElement) {
|
| - ExecutableElement foundElt = null;
|
| - String executableName = executableElement.name;
|
| - if (executableElement is MethodElement) {
|
| - foundElt = classElement.getMethod(executableName);
|
| - if (foundElt != null && !foundElt.isAbstract) {
|
| - return true;
|
| - }
|
| - List<InterfaceType> mixins = classElement.mixins;
|
| - for (int i = 0; i < mixins.length && foundElt == null; i++) {
|
| - foundElt = mixins[i].getMethod(executableName);
|
| - }
|
| - if (foundElt != null && !foundElt.isAbstract) {
|
| - return true;
|
| - }
|
| - } else if (executableElement is PropertyAccessorElement) {
|
| - if (executableElement.isGetter) {
|
| - foundElt = classElement.getGetter(executableName);
|
| - }
|
| - if (foundElt == null && executableElement.isSetter) {
|
| - foundElt = classElement.getSetter(executableName);
|
| - }
|
| - if (foundElt != null &&
|
| - !(foundElt as PropertyAccessorElement).isAbstract) {
|
| - return true;
|
| - }
|
| - List<InterfaceType> mixins = classElement.mixins;
|
| - for (int i = 0; i < mixins.length && foundElt == null; i++) {
|
| - foundElt = mixins[i].getGetter(executableName);
|
| - if (foundElt == null) {
|
| - foundElt = mixins[i].getSetter(executableName);
|
| - }
|
| - }
|
| - if (foundElt != null && !foundElt.isAbstract) {
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - /**
|
| * Return `true` if the given 'this' [expression] is in a valid context.
|
| */
|
| bool _isThisInValidContext(ThisExpression expression) {
|
| @@ -6712,6 +6573,106 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
| }
|
|
|
| /**
|
| + * Returns [ExecutableElement]s that are declared in interfaces implemented
|
| + * by the [classElement], but not implemented by the [classElement] or its
|
| + * superclasses.
|
| + */
|
| + static Set<ExecutableElement> computeMissingOverrides(
|
| + bool strongMode,
|
| + TypeProvider typeProvider,
|
| + TypeSystem typeSystem,
|
| + InheritanceManager inheritanceManager,
|
| + ClassElement classElement) {
|
| + //
|
| + // Store in local sets the set of all method and accessor names
|
| + //
|
| + HashSet<ExecutableElement> missingOverrides =
|
| + new HashSet<ExecutableElement>();
|
| + //
|
| + // Loop through the set of all executable elements declared in the implicit
|
| + // interface.
|
| + //
|
| + Map<String, ExecutableElement> membersInheritedFromInterfaces =
|
| + inheritanceManager.getMembersInheritedFromInterfaces(classElement);
|
| + Map<String, ExecutableElement> membersInheritedFromSuperclasses =
|
| + inheritanceManager.getMembersInheritedFromClasses(classElement);
|
| + for (String memberName in membersInheritedFromInterfaces.keys) {
|
| + ExecutableElement executableElt =
|
| + membersInheritedFromInterfaces[memberName];
|
| + if (memberName == null) {
|
| + break;
|
| + }
|
| + // If the element is not synthetic and can be determined to be defined in
|
| + // Object, skip it.
|
| + if (executableElt.enclosingElement != null &&
|
| + (executableElt.enclosingElement as ClassElement).type.isObject) {
|
| + continue;
|
| + }
|
| + // Check to see if some element is in local enclosing class that matches
|
| + // the name of the required member.
|
| + if (_isMemberInClassOrMixin(executableElt, classElement)) {
|
| + // We do not have to verify that this implementation of the found method
|
| + // matches the required function type: the set of
|
| + // StaticWarningCode.INVALID_METHOD_OVERRIDE_* warnings break out the
|
| + // different specific situations.
|
| + continue;
|
| + }
|
| + // First check to see if this element was declared in the superclass
|
| + // chain, in which case there is already a concrete implementation.
|
| + ExecutableElement elt = membersInheritedFromSuperclasses[memberName];
|
| + // Check to see if an element was found in the superclass chain with the
|
| + // correct name.
|
| + if (elt != null) {
|
| + // Reference the types, if any are null then continue.
|
| + InterfaceType enclosingType = classElement.type;
|
| + FunctionType concreteType = elt.type;
|
| + FunctionType requiredMemberType = executableElt.type;
|
| + if (enclosingType == null ||
|
| + concreteType == null ||
|
| + requiredMemberType == null) {
|
| + continue;
|
| + }
|
| + // Some element was found in the superclass chain that matches the name
|
| + // of the required member.
|
| + // If it is not abstract and it is the correct one (types match- the
|
| + // version of this method that we have has the correct number of
|
| + // parameters, etc), then this class has a valid implementation of this
|
| + // method, so skip it.
|
| + if ((elt is MethodElement && !elt.isAbstract) ||
|
| + (elt is PropertyAccessorElement && !elt.isAbstract)) {
|
| + // Since we are comparing two function types, we need to do the
|
| + // appropriate type substitutions first ().
|
| + FunctionType foundConcreteFT =
|
| + inheritanceManager.substituteTypeArgumentsInMemberFromInheritance(
|
| + concreteType, memberName, enclosingType);
|
| + FunctionType requiredMemberFT =
|
| + inheritanceManager.substituteTypeArgumentsInMemberFromInheritance(
|
| + requiredMemberType, memberName, enclosingType);
|
| + foundConcreteFT = typeSystem.functionTypeToConcreteType(
|
| + typeProvider, foundConcreteFT);
|
| + requiredMemberFT = typeSystem.functionTypeToConcreteType(
|
| + typeProvider, requiredMemberFT);
|
| +
|
| + // Strong mode does override checking for types in CodeChecker, so
|
| + // we can skip it here. Doing it here leads to unnecessary duplicate
|
| + // error messages in subclasses that inherit from one that has an
|
| + // override error.
|
| + //
|
| + // See: https://github.com/dart-lang/sdk/issues/25232
|
| + if (strongMode ||
|
| + typeSystem.isSubtypeOf(foundConcreteFT, requiredMemberFT)) {
|
| + continue;
|
| + }
|
| + }
|
| + }
|
| + // The not qualifying concrete executable element was found, add it to the
|
| + // list.
|
| + missingOverrides.add(executableElt);
|
| + }
|
| + return missingOverrides;
|
| + }
|
| +
|
| + /**
|
| * Return the static type of the given [expression] that is to be used for
|
| * type analysis.
|
| */
|
| @@ -6737,6 +6698,57 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
| }
|
| return null;
|
| }
|
| +
|
| + /**
|
| + * Return `true` iff the given [classElement] has a concrete method, getter or
|
| + * setter that matches the name of the given [executableElement] in either the
|
| + * class itself, or one of its' mixins.
|
| + *
|
| + * By "match", only the name of the member is tested to match, it does not
|
| + * have to equal or be a subtype of the given executable element, this is due
|
| + * to the specific use where this method is used in
|
| + * [_checkForNonAbstractClassInheritsAbstractMember].
|
| + */
|
| + static bool _isMemberInClassOrMixin(
|
| + ExecutableElement executableElement, ClassElement classElement) {
|
| + ExecutableElement foundElt = null;
|
| + String executableName = executableElement.name;
|
| + if (executableElement is MethodElement) {
|
| + foundElt = classElement.getMethod(executableName);
|
| + if (foundElt != null && !foundElt.isAbstract) {
|
| + return true;
|
| + }
|
| + List<InterfaceType> mixins = classElement.mixins;
|
| + for (int i = 0; i < mixins.length && foundElt == null; i++) {
|
| + foundElt = mixins[i].getMethod(executableName);
|
| + }
|
| + if (foundElt != null && !foundElt.isAbstract) {
|
| + return true;
|
| + }
|
| + } else if (executableElement is PropertyAccessorElement) {
|
| + if (executableElement.isGetter) {
|
| + foundElt = classElement.getGetter(executableName);
|
| + }
|
| + if (foundElt == null && executableElement.isSetter) {
|
| + foundElt = classElement.getSetter(executableName);
|
| + }
|
| + if (foundElt != null &&
|
| + !(foundElt as PropertyAccessorElement).isAbstract) {
|
| + return true;
|
| + }
|
| + List<InterfaceType> mixins = classElement.mixins;
|
| + for (int i = 0; i < mixins.length && foundElt == null; i++) {
|
| + foundElt = mixins[i].getGetter(executableName);
|
| + if (foundElt == null) {
|
| + foundElt = mixins[i].getSetter(executableName);
|
| + }
|
| + }
|
| + if (foundElt != null && !foundElt.isAbstract) {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| }
|
|
|
| class GeneralizingElementVisitor_ErrorVerifier_hasTypedefSelfReference
|
|
|