Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(273)

Side by Side Diff: pkg/analyzer/lib/src/generated/resolver.dart

Issue 1723243002: Validation of `@protected` method invocations. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: fixes Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library analyzer.src.generated.resolver; 5 library analyzer.src.generated.resolver;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 8
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart'; 10 import 'package:analyzer/dart/ast/token.dart';
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 // This was determined to not be a good hint, see: dartbug.com/16029 199 // This was determined to not be a good hint, see: dartbug.com/16029
200 //checkForOverridingPrivateMember(node); 200 //checkForOverridingPrivateMember(node);
201 _checkForMissingReturn(node.returnType, node.body); 201 _checkForMissingReturn(node.returnType, node.body);
202 _checkForUnnecessaryNoSuchMethod(node); 202 _checkForUnnecessaryNoSuchMethod(node);
203 return super.visitMethodDeclaration(node); 203 return super.visitMethodDeclaration(node);
204 } 204 }
205 205
206 @override 206 @override
207 Object visitMethodInvocation(MethodInvocation node) { 207 Object visitMethodInvocation(MethodInvocation node) {
208 _checkForCanBeNullAfterNullAware(node.realTarget, node.operator); 208 _checkForCanBeNullAfterNullAware(node.realTarget, node.operator);
209 _checkForInvalidProtectedMethodCalls(node);
209 return super.visitMethodInvocation(node); 210 return super.visitMethodInvocation(node);
210 } 211 }
211 212
212 @override 213 @override
213 Object visitPostfixExpression(PostfixExpression node) { 214 Object visitPostfixExpression(PostfixExpression node) {
214 _checkForDeprecatedMemberUse(node.bestElement, node); 215 _checkForDeprecatedMemberUse(node.bestElement, node);
215 return super.visitPostfixExpression(node); 216 return super.visitPostfixExpression(node);
216 } 217 }
217 218
218 @override 219 @override
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after
601 if (!_typeSystem.isAssignableTo(bestRightType, leftType)) { 602 if (!_typeSystem.isAssignableTo(bestRightType, leftType)) {
602 _errorReporter.reportTypeErrorForNode( 603 _errorReporter.reportTypeErrorForNode(
603 HintCode.INVALID_ASSIGNMENT, rhs, [bestRightType, leftType]); 604 HintCode.INVALID_ASSIGNMENT, rhs, [bestRightType, leftType]);
604 return true; 605 return true;
605 } 606 }
606 } 607 }
607 return false; 608 return false;
608 } 609 }
609 610
610 /** 611 /**
612 * Produces a hint if the given invocation is of a protected method outside
613 * a subclass instance method.
614 */
615 void _checkForInvalidProtectedMethodCalls(MethodInvocation node) {
616 Element element = node.methodName.bestElement;
617 if (element == null || !element.isProtected) {
618 return;
619 }
620
621 ClassElement definingClass = element.enclosingElement;
622
623 MethodDeclaration decl =
624 node.getAncestor((AstNode node) => node is MethodDeclaration);
625 if (decl == null) {
Brian Wilkerson 2016/02/23 23:42:57 Are we handling static methods as a call site? cl
pquitslund 2016/02/24 17:12:17 Yep. Test added!
626 _errorReporter.reportErrorForNode(
627 HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
628 node,
629 [node.methodName.toString(), definingClass.name]);
630 return;
631 }
632
633 ClassElement invokingClass = decl.element?.enclosingElement;
634 if (invokingClass != null) {
635 if (!_hasSuperClassOrMixin(invokingClass, definingClass.type)) {
636 _errorReporter.reportErrorForNode(
637 HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
638 node,
639 [node.methodName.toString(), definingClass.name]);
640 }
641 }
642 }
643
644 /**
611 * Check that the imported library does not define a loadLibrary function. The import has already 645 * Check that the imported library does not define a loadLibrary function. The import has already
612 * been determined to be deferred when this is called. 646 * been determined to be deferred when this is called.
613 * 647 *
614 * @param node the import directive to evaluate 648 * @param node the import directive to evaluate
615 * @param importElement the [ImportElement] retrieved from the node 649 * @param importElement the [ImportElement] retrieved from the node
616 * @return `true` if and only if an error code is generated on the passed node 650 * @return `true` if and only if an error code is generated on the passed node
617 * See [CompileTimeErrorCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION]. 651 * See [CompileTimeErrorCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION].
618 */ 652 */
619 bool _checkForLoadLibraryFunction( 653 bool _checkForLoadLibraryFunction(
620 ImportDirective node, ImportElement importElement) { 654 ImportDirective node, ImportElement importElement) {
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
783 !lhsType.isDynamic && 817 !lhsType.isDynamic &&
784 !rhsType.isDynamic && 818 !rhsType.isDynamic &&
785 lhsType.isMoreSpecificThan(rhsType)) { 819 lhsType.isMoreSpecificThan(rhsType)) {
786 _errorReporter.reportErrorForNode(HintCode.UNNECESSARY_CAST, node); 820 _errorReporter.reportErrorForNode(HintCode.UNNECESSARY_CAST, node);
787 return true; 821 return true;
788 } 822 }
789 return false; 823 return false;
790 } 824 }
791 825
792 /** 826 /**
793 * Check for the passed class declaration for the
794 * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
795 *
796 * @param node the class declaration to check
797 * @return `true` if and only if a hint code is generated on the passed node
798 * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE].
799 */
800 // bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) {
801 // ClassElement classElement = node.element;
802 // if (classElement == null) {
803 // return false;
804 // }
805 // MethodElement equalsOperatorMethodElement =
806 // classElement.getMethod(sc.TokenType.EQ_EQ.lexeme);
807 // if (equalsOperatorMethodElement != null) {
808 // PropertyAccessorElement hashCodeElement =
809 // classElement.getGetter(_HASHCODE_GETTER_NAME);
810 // if (hashCodeElement == null) {
811 // _errorReporter.reportErrorForNode(
812 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE,
813 // node.name,
814 // [classElement.displayName]);
815 // return true;
816 // }
817 // }
818 // return false;
819 // }
820
821 /**
822 * Generate a hint for `noSuchMethod` methods that do nothing except of 827 * Generate a hint for `noSuchMethod` methods that do nothing except of
823 * calling another `noSuchMethod` that is not defined by `Object`. 828 * calling another `noSuchMethod` that is not defined by `Object`.
824 * 829 *
825 * @return `true` if and only if a hint code is generated on the passed node 830 * @return `true` if and only if a hint code is generated on the passed node
826 * See [HintCode.UNNECESSARY_NO_SUCH_METHOD]. 831 * See [HintCode.UNNECESSARY_NO_SUCH_METHOD].
827 */ 832 */
828 bool _checkForUnnecessaryNoSuchMethod(MethodDeclaration node) { 833 bool _checkForUnnecessaryNoSuchMethod(MethodDeclaration node) {
829 if (node.name.name != FunctionElement.NO_SUCH_METHOD_METHOD_NAME) { 834 if (node.name.name != FunctionElement.NO_SUCH_METHOD_METHOD_NAME) {
830 return false; 835 return false;
831 } 836 }
(...skipping 28 matching lines...) Expand all
860 _errorReporter.reportErrorForNode( 865 _errorReporter.reportErrorForNode(
861 HintCode.UNNECESSARY_NO_SUCH_METHOD, node); 866 HintCode.UNNECESSARY_NO_SUCH_METHOD, node);
862 return true; 867 return true;
863 } 868 }
864 } 869 }
865 } 870 }
866 return false; 871 return false;
867 } 872 }
868 873
869 /** 874 /**
875 * Check for the passed class declaration for the
876 * [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
877 *
878 * @param node the class declaration to check
879 * @return `true` if and only if a hint code is generated on the passed node
880 * See [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE].
881 */
882 // bool _checkForOverrideEqualsButNotHashCode(ClassDeclaration node) {
883 // ClassElement classElement = node.element;
884 // if (classElement == null) {
885 // return false;
886 // }
887 // MethodElement equalsOperatorMethodElement =
888 // classElement.getMethod(sc.TokenType.EQ_EQ.lexeme);
889 // if (equalsOperatorMethodElement != null) {
890 // PropertyAccessorElement hashCodeElement =
891 // classElement.getGetter(_HASHCODE_GETTER_NAME);
892 // if (hashCodeElement == null) {
893 // _errorReporter.reportErrorForNode(
894 // HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE,
895 // node.name,
896 // [classElement.displayName]);
897 // return true;
898 // }
899 // }
900 // return false;
901 // }
902
903 /**
870 * Check for situations where the result of a method or function is used, when it returns 'void'. 904 * Check for situations where the result of a method or function is used, when it returns 'void'.
871 * 905 *
872 * TODO(jwren) Many other situations of use could be covered. We currently cov er the cases var x = 906 * TODO(jwren) Many other situations of use could be covered. We currently cov er the cases var x =
873 * m() and x = m(), but we could also cover cases such as m().x, m()[k], a + m (), f(m()), return 907 * m() and x = m(), but we could also cover cases such as m().x, m()[k], a + m (), f(m()), return
874 * m(). 908 * m().
875 * 909 *
876 * @param node expression on the RHS of some assignment 910 * @param node expression on the RHS of some assignment
877 * @return `true` if and only if a hint code is generated on the passed node 911 * @return `true` if and only if a hint code is generated on the passed node
878 * See [HintCode.USE_OF_VOID_RESULT]. 912 * See [HintCode.USE_OF_VOID_RESULT].
879 */ 913 */
880 bool _checkForUseOfVoidResult(Expression expression) { 914 bool _checkForUseOfVoidResult(Expression expression) {
881 if (expression == null || expression is! MethodInvocation) { 915 if (expression == null || expression is! MethodInvocation) {
882 return false; 916 return false;
883 } 917 }
884 MethodInvocation methodInvocation = expression as MethodInvocation; 918 MethodInvocation methodInvocation = expression as MethodInvocation;
885 if (identical(methodInvocation.staticType, VoidTypeImpl.instance)) { 919 if (identical(methodInvocation.staticType, VoidTypeImpl.instance)) {
886 SimpleIdentifier methodName = methodInvocation.methodName; 920 SimpleIdentifier methodName = methodInvocation.methodName;
887 _errorReporter.reportErrorForNode( 921 _errorReporter.reportErrorForNode(
888 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]); 922 HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]);
889 return true; 923 return true;
890 } 924 }
891 return false; 925 return false;
892 } 926 }
893 927
928 bool _hasSuperClassOrMixin(ClassElement element, InterfaceType type) {
929 List<ClassElement> seenClasses = <ClassElement>[];
930 while (element != null && !seenClasses.contains(element)) {
931 if (element.type == type) {
932 return true;
933 }
934
935 if (element.mixins.any((InterfaceType t) => t == type)) {
936 return true;
937 }
938
939 seenClasses.add(element);
940 element = element.supertype?.element;
941 }
942
943 return false;
944 }
945
894 /** 946 /**
895 * Given a parenthesized expression, this returns the parent (or recursively g rand-parent) of the 947 * Given a parenthesized expression, this returns the parent (or recursively g rand-parent) of the
896 * expression that is a parenthesized expression, but whose parent is not a pa renthesized 948 * expression that is a parenthesized expression, but whose parent is not a pa renthesized
897 * expression. 949 * expression.
898 * 950 *
899 * For example given the code `(((e)))`: `(e) -> (((e)))`. 951 * For example given the code `(((e)))`: `(e) -> (((e)))`.
900 * 952 *
901 * @param parenthesizedExpression some expression whose parent is a parenthesi zed expression 953 * @param parenthesizedExpression some expression whose parent is a parenthesi zed expression
902 * @return the first parent or grand-parent that is a parenthesized expression , that does not have 954 * @return the first parent or grand-parent that is a parenthesized expression , that does not have
903 * a parenthesized expression parent 955 * a parenthesized expression parent
(...skipping 7476 matching lines...) Expand 10 before | Expand all | Expand 10 after
8380 safelyVisit(node.target); 8432 safelyVisit(node.target);
8381 safelyVisit(node.typeArguments); 8433 safelyVisit(node.typeArguments);
8382 node.accept(elementResolver); 8434 node.accept(elementResolver);
8383 _inferFunctionExpressionsParametersTypes(node.argumentList); 8435 _inferFunctionExpressionsParametersTypes(node.argumentList);
8384 _inferArgumentTypesFromContext(node); 8436 _inferArgumentTypesFromContext(node);
8385 safelyVisit(node.argumentList); 8437 safelyVisit(node.argumentList);
8386 node.accept(typeAnalyzer); 8438 node.accept(typeAnalyzer);
8387 return null; 8439 return null;
8388 } 8440 }
8389 8441
8390 void _inferArgumentTypesFromContext(InvocationExpression node) {
8391 DartType contextType = node.staticInvokeType;
8392 if (contextType is FunctionType) {
8393 DartType originalType = node.function.staticType;
8394 DartType returnContextType = InferenceContext.getType(node);
8395 TypeSystem ts = typeSystem;
8396 if (returnContextType != null &&
8397 node.typeArguments == null &&
8398 originalType is FunctionType &&
8399 originalType.typeFormals.isNotEmpty &&
8400 ts is StrongTypeSystemImpl) {
8401
8402 contextType = ts.inferGenericFunctionCall(typeProvider, originalType,
8403 DartType.EMPTY_LIST, DartType.EMPTY_LIST, returnContextType);
8404 }
8405
8406 InferenceContext.setType(node.argumentList, contextType);
8407 }
8408 }
8409
8410 @override 8442 @override
8411 Object visitNamedExpression(NamedExpression node) { 8443 Object visitNamedExpression(NamedExpression node) {
8412 InferenceContext.setType(node.expression, InferenceContext.getType(node)); 8444 InferenceContext.setType(node.expression, InferenceContext.getType(node));
8413 return super.visitNamedExpression(node); 8445 return super.visitNamedExpression(node);
8414 } 8446 }
8415 8447
8416 @override 8448 @override
8417 Object visitNode(AstNode node) { 8449 Object visitNode(AstNode node) {
8418 node.visitChildren(this); 8450 node.visitChildren(this);
8419 node.accept(elementResolver); 8451 node.accept(elementResolver);
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after
8727 List<ParameterElement> onDataParameters = onDataType.parameters; 8759 List<ParameterElement> onDataParameters = onDataType.parameters;
8728 if (onDataParameters == null || onDataParameters.isEmpty) { 8760 if (onDataParameters == null || onDataParameters.isEmpty) {
8729 return null; 8761 return null;
8730 } 8762 }
8731 return onDataParameters[0].type; 8763 return onDataParameters[0].type;
8732 } 8764 }
8733 } 8765 }
8734 return null; 8766 return null;
8735 } 8767 }
8736 8768
8769 void _inferArgumentTypesFromContext(InvocationExpression node) {
8770 DartType contextType = node.staticInvokeType;
8771 if (contextType is FunctionType) {
8772 DartType originalType = node.function.staticType;
8773 DartType returnContextType = InferenceContext.getType(node);
8774 TypeSystem ts = typeSystem;
8775 if (returnContextType != null &&
8776 node.typeArguments == null &&
8777 originalType is FunctionType &&
8778 originalType.typeFormals.isNotEmpty &&
8779 ts is StrongTypeSystemImpl) {
8780 contextType = ts.inferGenericFunctionCall(typeProvider, originalType,
8781 DartType.EMPTY_LIST, DartType.EMPTY_LIST, returnContextType);
8782 }
8783
8784 InferenceContext.setType(node.argumentList, contextType);
8785 }
8786 }
8787
8737 void _inferFormalParameterList(FormalParameterList node, DartType type) { 8788 void _inferFormalParameterList(FormalParameterList node, DartType type) {
8738 if (typeAnalyzer.inferFormalParameterList(node, type)) { 8789 if (typeAnalyzer.inferFormalParameterList(node, type)) {
8739 // TODO(leafp): This gets dropped on the floor if we're in the field 8790 // TODO(leafp): This gets dropped on the floor if we're in the field
8740 // inference task. We should probably keep these infos. 8791 // inference task. We should probably keep these infos.
8741 inferenceContext.recordInference(node.parent, type); 8792 inferenceContext.recordInference(node.parent, type);
8742 } 8793 }
8743 } 8794 }
8744 8795
8745 /** 8796 /**
8746 * If given "mayBeClosure" is [FunctionExpression] without explicit parameters types and its 8797 * If given "mayBeClosure" is [FunctionExpression] without explicit parameters types and its
(...skipping 4053 matching lines...) Expand 10 before | Expand all | Expand 10 after
12800 nonFields.add(node); 12851 nonFields.add(node);
12801 return null; 12852 return null;
12802 } 12853 }
12803 12854
12804 @override 12855 @override
12805 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this); 12856 Object visitNode(AstNode node) => node.accept(TypeResolverVisitor_this);
12806 12857
12807 @override 12858 @override
12808 Object visitWithClause(WithClause node) => null; 12859 Object visitWithClause(WithClause node) => null;
12809 } 12860 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698