| OLD | NEW |
| 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.error_verifier; | 5 library analyzer.src.generated.error_verifier; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 import "dart:math" as math; | 8 import "dart:math" as math; |
| 9 | 9 |
| 10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
| 11 import 'package:analyzer/dart/ast/token.dart'; | 11 import 'package:analyzer/dart/ast/token.dart'; |
| 12 import 'package:analyzer/dart/ast/visitor.dart'; | 12 import 'package:analyzer/dart/ast/visitor.dart'; |
| 13 import 'package:analyzer/dart/element/element.dart'; | 13 import 'package:analyzer/dart/element/element.dart'; |
| 14 import 'package:analyzer/dart/element/type.dart'; | 14 import 'package:analyzer/dart/element/type.dart'; |
| 15 import 'package:analyzer/dart/element/visitor.dart'; | 15 import 'package:analyzer/dart/element/visitor.dart'; |
| 16 import 'package:analyzer/src/dart/ast/utilities.dart'; | 16 import 'package:analyzer/src/dart/ast/utilities.dart'; |
| 17 import 'package:analyzer/src/dart/element/element.dart'; | 17 import 'package:analyzer/src/dart/element/element.dart'; |
| 18 import 'package:analyzer/src/dart/element/member.dart'; | 18 import 'package:analyzer/src/dart/element/member.dart'; |
| 19 import 'package:analyzer/src/dart/element/type.dart'; | 19 import 'package:analyzer/src/dart/element/type.dart'; |
| 20 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart'; | 20 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart'; |
| 21 import 'package:analyzer/src/error/pending_error.dart'; |
| 21 import 'package:analyzer/src/generated/constant.dart'; | 22 import 'package:analyzer/src/generated/constant.dart'; |
| 22 import 'package:analyzer/src/generated/element_resolver.dart'; | 23 import 'package:analyzer/src/generated/element_resolver.dart'; |
| 23 import 'package:analyzer/src/generated/engine.dart'; | 24 import 'package:analyzer/src/generated/engine.dart'; |
| 24 import 'package:analyzer/src/generated/error.dart'; | 25 import 'package:analyzer/src/generated/error.dart'; |
| 25 import 'package:analyzer/src/generated/java_engine.dart'; | 26 import 'package:analyzer/src/generated/java_engine.dart'; |
| 26 import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode; | 27 import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode; |
| 27 import 'package:analyzer/src/generated/resolver.dart'; | 28 import 'package:analyzer/src/generated/resolver.dart'; |
| 28 import 'package:analyzer/src/generated/sdk.dart' show DartSdk, SdkLibrary; | 29 import 'package:analyzer/src/generated/sdk.dart' show DartSdk, SdkLibrary; |
| 30 import 'package:analyzer/src/generated/source.dart'; |
| 29 import 'package:analyzer/src/generated/utilities_dart.dart'; | 31 import 'package:analyzer/src/generated/utilities_dart.dart'; |
| 32 import 'package:analyzer/src/task/dart.dart'; |
| 30 import 'package:analyzer/src/task/strong/info.dart' show StaticInfo; | 33 import 'package:analyzer/src/task/strong/info.dart' show StaticInfo; |
| 31 | 34 |
| 32 /** | 35 /** |
| 33 * A visitor used to traverse an AST structure looking for additional errors and | 36 * A visitor used to traverse an AST structure looking for additional errors and |
| 34 * warnings not covered by the parser and resolver. | 37 * warnings not covered by the parser and resolver. |
| 35 */ | 38 */ |
| 36 class ErrorVerifier extends RecursiveAstVisitor<Object> { | 39 class ErrorVerifier extends RecursiveAstVisitor<Object> { |
| 37 /** | 40 /** |
| 38 * Static final string with value `"getter "` used in the construction of the | 41 * Static final string with value `"getter "` used in the construction of the |
| 39 * [StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE], and | 42 * [StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE], and |
| (...skipping 782 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 822 Object visitInstanceCreationExpression(InstanceCreationExpression node) { | 825 Object visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 823 bool wasInConstInstanceCreation = _isInConstInstanceCreation; | 826 bool wasInConstInstanceCreation = _isInConstInstanceCreation; |
| 824 _isInConstInstanceCreation = node.isConst; | 827 _isInConstInstanceCreation = node.isConst; |
| 825 try { | 828 try { |
| 826 ConstructorName constructorName = node.constructorName; | 829 ConstructorName constructorName = node.constructorName; |
| 827 TypeName typeName = constructorName.type; | 830 TypeName typeName = constructorName.type; |
| 828 DartType type = typeName.type; | 831 DartType type = typeName.type; |
| 829 if (type is InterfaceType) { | 832 if (type is InterfaceType) { |
| 830 _checkForConstOrNewWithAbstractClass(node, typeName, type); | 833 _checkForConstOrNewWithAbstractClass(node, typeName, type); |
| 831 _checkForConstOrNewWithEnum(node, typeName, type); | 834 _checkForConstOrNewWithEnum(node, typeName, type); |
| 832 _checkForMissingRequiredParam( | |
| 833 node.staticElement?.type, node.argumentList, node.constructorName); | |
| 834 if (_isInConstInstanceCreation) { | 835 if (_isInConstInstanceCreation) { |
| 835 _checkForConstWithNonConst(node); | 836 _checkForConstWithNonConst(node); |
| 836 _checkForConstWithUndefinedConstructor( | 837 _checkForConstWithUndefinedConstructor( |
| 837 node, constructorName, typeName); | 838 node, constructorName, typeName); |
| 838 _checkForConstWithTypeParameters(typeName); | 839 _checkForConstWithTypeParameters(typeName); |
| 839 _checkForConstDeferredClass(node, constructorName, typeName); | 840 _checkForConstDeferredClass(node, constructorName, typeName); |
| 840 } else { | 841 } else { |
| 841 _checkForNewWithUndefinedConstructor(node, constructorName, typeName); | 842 _checkForNewWithUndefinedConstructor(node, constructorName, typeName); |
| 842 } | 843 } |
| 843 } | 844 } |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 935 Object visitMethodInvocation(MethodInvocation node) { | 936 Object visitMethodInvocation(MethodInvocation node) { |
| 936 Expression target = node.realTarget; | 937 Expression target = node.realTarget; |
| 937 SimpleIdentifier methodName = node.methodName; | 938 SimpleIdentifier methodName = node.methodName; |
| 938 if (target != null) { | 939 if (target != null) { |
| 939 ClassElement typeReference = ElementResolver.getTypeReference(target); | 940 ClassElement typeReference = ElementResolver.getTypeReference(target); |
| 940 _checkForStaticAccessToInstanceMember(typeReference, methodName); | 941 _checkForStaticAccessToInstanceMember(typeReference, methodName); |
| 941 _checkForInstanceAccessToStaticMember(typeReference, methodName); | 942 _checkForInstanceAccessToStaticMember(typeReference, methodName); |
| 942 } else { | 943 } else { |
| 943 _checkForUnqualifiedReferenceToNonLocalStaticMember(methodName); | 944 _checkForUnqualifiedReferenceToNonLocalStaticMember(methodName); |
| 944 } | 945 } |
| 945 _checkForMissingRequiredParam( | |
| 946 node.staticInvokeType, node.argumentList, methodName); | |
| 947 _checkTypeArguments( | 946 _checkTypeArguments( |
| 948 node.methodName.staticElement, node.typeArguments, target?.staticType); | 947 node.methodName.staticElement, node.typeArguments, target?.staticType); |
| 949 return super.visitMethodInvocation(node); | 948 return super.visitMethodInvocation(node); |
| 950 } | 949 } |
| 951 | 950 |
| 952 @override | 951 @override |
| 953 Object visitNativeClause(NativeClause node) { | 952 Object visitNativeClause(NativeClause node) { |
| 954 // TODO(brianwilkerson) Figure out the right rule for when 'native' is | 953 // TODO(brianwilkerson) Figure out the right rule for when 'native' is |
| 955 // allowed. | 954 // allowed. |
| 956 if (!_isInSystemLibrary) { | 955 if (!_isInSystemLibrary) { |
| (...skipping 3282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4239 void _checkForMissingJSLibAnnotation(Annotation node) { | 4238 void _checkForMissingJSLibAnnotation(Annotation node) { |
| 4240 if (node.elementAnnotation?.isJS ?? false) { | 4239 if (node.elementAnnotation?.isJS ?? false) { |
| 4241 Element element = ElementLocator.locate(node.parent); | 4240 Element element = ElementLocator.locate(node.parent); |
| 4242 if (element?.library?.isJS != true) { | 4241 if (element?.library?.isJS != true) { |
| 4243 _errorReporter.reportErrorForNode( | 4242 _errorReporter.reportErrorForNode( |
| 4244 HintCode.MISSING_JS_LIB_ANNOTATION, node, [element.name]); | 4243 HintCode.MISSING_JS_LIB_ANNOTATION, node, [element.name]); |
| 4245 } | 4244 } |
| 4246 } | 4245 } |
| 4247 } | 4246 } |
| 4248 | 4247 |
| 4249 void _checkForMissingRequiredParam( | |
| 4250 DartType type, ArgumentList argumentList, AstNode node) { | |
| 4251 if (type is FunctionType) { | |
| 4252 List<ParameterElement> parameters = type.parameters; | |
| 4253 for (ParameterElement param in parameters) { | |
| 4254 if (param.parameterKind == ParameterKind.NAMED) { | |
| 4255 ElementAnnotationImpl annotation = _getRequiredAnnotation(param); | |
| 4256 if (annotation != null) { | |
| 4257 String paramName = param.name; | |
| 4258 if (!_containsNamedExpression(argumentList, paramName)) { | |
| 4259 DartObject constantValue = annotation.constantValue; | |
| 4260 String reason = | |
| 4261 constantValue?.getField('reason')?.toStringValue(); | |
| 4262 if (reason != null) { | |
| 4263 _errorReporter.reportErrorForNode( | |
| 4264 HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS, | |
| 4265 node, | |
| 4266 [paramName, reason]); | |
| 4267 } else { | |
| 4268 _errorReporter.reportErrorForNode( | |
| 4269 HintCode.MISSING_REQUIRED_PARAM, node, [paramName]); | |
| 4270 } | |
| 4271 } | |
| 4272 } | |
| 4273 } | |
| 4274 } | |
| 4275 } | |
| 4276 } | |
| 4277 | |
| 4278 /** | 4248 /** |
| 4279 * Verify that the given function [body] does not contain return statements | 4249 * Verify that the given function [body] does not contain return statements |
| 4280 * that both have and do not have return values. | 4250 * that both have and do not have return values. |
| 4281 * | 4251 * |
| 4282 * See [StaticWarningCode.MIXED_RETURN_TYPES]. | 4252 * See [StaticWarningCode.MIXED_RETURN_TYPES]. |
| 4283 */ | 4253 */ |
| 4284 void _checkForMixedReturns(BlockFunctionBody body) { | 4254 void _checkForMixedReturns(BlockFunctionBody body) { |
| 4285 if (_hasReturnWithoutValue) { | 4255 if (_hasReturnWithoutValue) { |
| 4286 return; | 4256 return; |
| 4287 } | 4257 } |
| (...skipping 1466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5754 } | 5724 } |
| 5755 } | 5725 } |
| 5756 DartType staticReturnType = getStaticType(returnExpression); | 5726 DartType staticReturnType = getStaticType(returnExpression); |
| 5757 if (staticReturnType != null && _enclosingFunction.isAsynchronous) { | 5727 if (staticReturnType != null && _enclosingFunction.isAsynchronous) { |
| 5758 return _typeProvider.futureType.instantiate( | 5728 return _typeProvider.futureType.instantiate( |
| 5759 <DartType>[staticReturnType.flattenFutures(_typeSystem)]); | 5729 <DartType>[staticReturnType.flattenFutures(_typeSystem)]); |
| 5760 } | 5730 } |
| 5761 return staticReturnType; | 5731 return staticReturnType; |
| 5762 } | 5732 } |
| 5763 | 5733 |
| 5764 bool _containsNamedExpression(ArgumentList args, String name) { | |
| 5765 for (Expression expression in args.arguments) { | |
| 5766 if (expression is NamedExpression) { | |
| 5767 if (expression.name.label.name == name) { | |
| 5768 return true; | |
| 5769 } | |
| 5770 } | |
| 5771 } | |
| 5772 return false; | |
| 5773 } | |
| 5774 | |
| 5775 bool _expressionIsAssignableAtType(Expression expression, | 5734 bool _expressionIsAssignableAtType(Expression expression, |
| 5776 DartType actualStaticType, DartType expectedStaticType) { | 5735 DartType actualStaticType, DartType expectedStaticType) { |
| 5777 bool concrete = | 5736 bool concrete = |
| 5778 _options.strongMode && StaticInfo.isKnownFunction(expression); | 5737 _options.strongMode && StaticInfo.isKnownFunction(expression); |
| 5779 if (concrete) { | 5738 if (concrete) { |
| 5780 actualStaticType = | 5739 actualStaticType = |
| 5781 _typeSystem.typeToConcreteType(_typeProvider, actualStaticType); | 5740 _typeSystem.typeToConcreteType(_typeProvider, actualStaticType); |
| 5782 // TODO(leafp): Move the Downcast functionality here. | 5741 // TODO(leafp): Move the Downcast functionality here. |
| 5783 // TODO(leafp): Support strict downcasts | 5742 // TODO(leafp): Support strict downcasts |
| 5784 } | 5743 } |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5858 } | 5817 } |
| 5859 | 5818 |
| 5860 ClassElement classElement = | 5819 ClassElement classElement = |
| 5861 member.getAncestor((element) => element is ClassElement); | 5820 member.getAncestor((element) => element is ClassElement); |
| 5862 if (classElement == null) { | 5821 if (classElement == null) { |
| 5863 return null; | 5822 return null; |
| 5864 } | 5823 } |
| 5865 return _inheritanceManager.lookupInheritance(classElement, member.name); | 5824 return _inheritanceManager.lookupInheritance(classElement, member.name); |
| 5866 } | 5825 } |
| 5867 | 5826 |
| 5868 ElementAnnotationImpl _getRequiredAnnotation(ParameterElement param) => param | |
| 5869 .metadata | |
| 5870 .firstWhere((ElementAnnotation e) => e.isRequired, orElse: () => null); | |
| 5871 | |
| 5872 /** | 5827 /** |
| 5873 * Return the type of the first and only parameter of the given [setter]. | 5828 * Return the type of the first and only parameter of the given [setter]. |
| 5874 */ | 5829 */ |
| 5875 DartType _getSetterType(PropertyAccessorElement setter) { | 5830 DartType _getSetterType(PropertyAccessorElement setter) { |
| 5876 // Get the parameters for MethodDeclaration or FunctionDeclaration | 5831 // Get the parameters for MethodDeclaration or FunctionDeclaration |
| 5877 List<ParameterElement> setterParameters = setter.parameters; | 5832 List<ParameterElement> setterParameters = setter.parameters; |
| 5878 // If there are no setter parameters, return no type. | 5833 // If there are no setter parameters, return no type. |
| 5879 if (setterParameters.length == 0) { | 5834 if (setterParameters.length == 0) { |
| 5880 return null; | 5835 return null; |
| 5881 } | 5836 } |
| (...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6222 // type arguments | 6177 // type arguments |
| 6223 if (type is InterfaceType) { | 6178 if (type is InterfaceType) { |
| 6224 for (DartType typeArgument in type.typeArguments) { | 6179 for (DartType typeArgument in type.typeArguments) { |
| 6225 _addTypeToCheck(typeArgument); | 6180 _addTypeToCheck(typeArgument); |
| 6226 } | 6181 } |
| 6227 } | 6182 } |
| 6228 } | 6183 } |
| 6229 } | 6184 } |
| 6230 | 6185 |
| 6231 /** | 6186 /** |
| 6187 * A class used to compute a list of the constants whose value needs to be |
| 6188 * computed before errors can be computed by the [VerifyUnitTask]. |
| 6189 */ |
| 6190 class RequiredConstantsComputer extends RecursiveAstVisitor { |
| 6191 /** |
| 6192 * The source with which any pending errors will be associated. |
| 6193 */ |
| 6194 final Source source; |
| 6195 |
| 6196 /** |
| 6197 * A list of the pending errors that were computed. |
| 6198 */ |
| 6199 final List<PendingError> pendingErrors = <PendingError>[]; |
| 6200 |
| 6201 /** |
| 6202 * A list of the constants whose value needs to be computed before the pending |
| 6203 * errors can be used to compute an analysis error. |
| 6204 */ |
| 6205 final List<ConstantEvaluationTarget> requiredConstants = |
| 6206 <ConstantEvaluationTarget>[]; |
| 6207 |
| 6208 /** |
| 6209 * Initialize a newly created computer to compute required constants within |
| 6210 * the given [source]. |
| 6211 */ |
| 6212 RequiredConstantsComputer(this.source); |
| 6213 |
| 6214 @override |
| 6215 Object visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 6216 DartType type = node.constructorName.type.type; |
| 6217 if (type is InterfaceType) { |
| 6218 _checkForMissingRequiredParam( |
| 6219 node.staticElement?.type, node.argumentList, node.constructorName); |
| 6220 } |
| 6221 return super.visitInstanceCreationExpression(node); |
| 6222 } |
| 6223 |
| 6224 @override |
| 6225 Object visitMethodInvocation(MethodInvocation node) { |
| 6226 _checkForMissingRequiredParam( |
| 6227 node.staticInvokeType, node.argumentList, node.methodName); |
| 6228 return super.visitMethodInvocation(node); |
| 6229 } |
| 6230 |
| 6231 void _checkForMissingRequiredParam( |
| 6232 DartType type, ArgumentList argumentList, AstNode node) { |
| 6233 if (type is FunctionType) { |
| 6234 for (ParameterElement parameter in type.parameters) { |
| 6235 if (parameter.parameterKind == ParameterKind.NAMED) { |
| 6236 ElementAnnotationImpl annotation = _getRequiredAnnotation(parameter); |
| 6237 if (annotation != null) { |
| 6238 String parameterName = parameter.name; |
| 6239 if (!_containsNamedExpression(argumentList, parameterName)) { |
| 6240 requiredConstants.add(annotation); |
| 6241 pendingErrors.add(new PendingMissingRequiredParameterError( |
| 6242 source, parameterName, node, annotation)); |
| 6243 } |
| 6244 } |
| 6245 } |
| 6246 } |
| 6247 } |
| 6248 } |
| 6249 |
| 6250 bool _containsNamedExpression(ArgumentList args, String name) { |
| 6251 NodeList<Expression> arguments = args.arguments; |
| 6252 for (int i = arguments.length - 1; i >= 0; i--) { |
| 6253 Expression expression = arguments[i]; |
| 6254 if (expression is NamedExpression) { |
| 6255 if (expression.name.label.name == name) { |
| 6256 return true; |
| 6257 } |
| 6258 } |
| 6259 } |
| 6260 return false; |
| 6261 } |
| 6262 |
| 6263 ElementAnnotationImpl _getRequiredAnnotation(ParameterElement param) => param |
| 6264 .metadata |
| 6265 .firstWhere((ElementAnnotation e) => e.isRequired, orElse: () => null); |
| 6266 } |
| 6267 |
| 6268 /** |
| 6232 * Recursively visits an AST, looking for method invocations. | 6269 * Recursively visits an AST, looking for method invocations. |
| 6233 */ | 6270 */ |
| 6234 class _InvocationCollector extends RecursiveAstVisitor { | 6271 class _InvocationCollector extends RecursiveAstVisitor { |
| 6235 final List<String> superCalls = <String>[]; | 6272 final List<String> superCalls = <String>[]; |
| 6236 | 6273 |
| 6237 @override | 6274 @override |
| 6238 visitMethodInvocation(MethodInvocation node) { | 6275 visitMethodInvocation(MethodInvocation node) { |
| 6239 if (node.target is SuperExpression) { | 6276 if (node.target is SuperExpression) { |
| 6240 superCalls.add(node.methodName.name); | 6277 superCalls.add(node.methodName.name); |
| 6241 } | 6278 } |
| 6242 } | 6279 } |
| 6243 } | 6280 } |
| OLD | NEW |