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

Unified Diff: pkg/analyzer/test/src/task/strong/front_end_runtime_check_test.dart

Issue 3010613003: Simplify annotations in runtime check tests. (Closed)
Patch Set: Address code review comment Created 3 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/front_end/lib/src/fasta/testing/validating_instrumentation.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/test/src/task/strong/front_end_runtime_check_test.dart
diff --git a/pkg/analyzer/test/src/task/strong/front_end_runtime_check_test.dart b/pkg/analyzer/test/src/task/strong/front_end_runtime_check_test.dart
index 8ca85e62df2f2548a7be15529c863ca5f4ebe831..6f8d94553e3c195d259b1957286785570be18934 100644
--- a/pkg/analyzer/test/src/task/strong/front_end_runtime_check_test.dart
+++ b/pkg/analyzer/test/src/task/strong/front_end_runtime_check_test.dart
@@ -65,13 +65,11 @@ class _InstrumentationVisitor extends GeneralizingAstVisitor<Null> {
var staticElement = leftHandSide.identifier.staticElement;
if (staticElement is PropertyAccessorElement && staticElement.isSetter) {
var target = leftHandSide.prefix;
- _annotateCheckCall(
+ _annotateCallKind(
staticElement,
target is ThisExpression,
isDynamicInvoke(leftHandSide.identifier),
target.staticType,
- [],
- [node.rightHandSide],
leftHandSide.identifier.offset);
}
}
@@ -96,8 +94,10 @@ class _InstrumentationVisitor extends GeneralizingAstVisitor<Null> {
// Already handled via the contained parameter ast object
return;
}
- _annotateFormalParameter(node.element, node.identifier.offset,
- node.getAncestor((n) => n is ClassDeclaration));
+ if (node.element.enclosingElement.enclosingElement is ClassElement) {
+ _annotateFormalParameter(node.element, node.identifier.offset,
+ node.getAncestor((n) => n is ClassDeclaration));
+ }
}
@override
@@ -111,24 +111,12 @@ class _InstrumentationVisitor extends GeneralizingAstVisitor<Null> {
// function invocation.
_annotateCheckReturn(
getImplicitOperationCast(node), node.methodName.offset);
- _annotateCheckCall(
- null,
- isThis,
- isDynamicInvoke(node.methodName),
- null,
- node.typeArguments?.arguments,
- node.argumentList.arguments,
+ _annotateCallKind(null, isThis, isDynamicInvoke(node.methodName), null,
node.argumentList.offset);
} else {
_annotateCheckReturn(getImplicitCast(node), node.argumentList.offset);
- _annotateCheckCall(
- staticElement,
- isThis,
- isDynamicInvoke(node.methodName),
- target?.staticType,
- node.typeArguments?.arguments,
- node.argumentList.arguments,
- node.argumentList.offset);
+ _annotateCallKind(staticElement, isThis, isDynamicInvoke(node.methodName),
+ target?.staticType, node.argumentList.offset);
}
}
@@ -162,44 +150,21 @@ class _InstrumentationVisitor extends GeneralizingAstVisitor<Null> {
}
}
- /// Generates the appropriate `@checkCall` annotation (if any) for a call
- /// site.
+ /// Generates the appropriate `@callKind` annotation (if any) for a call site.
///
- /// An annotation of `@checkCall=dynamic` indicates that the call is dynamic
+ /// An annotation of `@callKind=dynamic` indicates that the call is dynamic
/// (so it will have to be fully type checked). An annotation of
- /// "@checkCall=interface(args)" indicates that the call statically resolves
- /// to a member of an interface, but some of the arguments are "semi-typed" so
- /// they may have to be type checked. `args` lists the positional indices of
- /// the semi-typed arguments (counting from 0). If any type parameters need
- /// to be checked, they are also listed by index, enclosed in `<>`. For
- /// example, `@checkCall=interface(<0>,1)` means that type parameter 0 and
- /// regular parameter 1 are semi-typed.
- ///
- /// [staticElement] is the element being invoked, or `null` if there is no
- /// static element (either because this is a dynamic invocation or because the
- /// thing being invoked is function-typed).
- ///
- /// [isThis] indicates whether the receiver of the invocation is `this`.
- ///
- /// [isDynamic] indicates whether analyzer has classified this invocation as a
- /// dynamic invocation.
- ///
- /// [targetType] is the type of the target of the invocation, or `null` if
- /// there is no target (e.g. because of implicit `this` or because the thing
- /// being invoked is function-typed).
- ///
- /// [typeArguments] and [arguments] are the type arguments and regular
- /// arguments of the invocation, respectively.
- ///
- /// [offset] is the location of the invocation in source code.
- void _annotateCheckCall(
- Element staticElement,
- bool isThis,
- bool isDynamic,
- DartType targetType,
- List<TypeAnnotation> typeArguments,
- List<Expression> arguments,
- int offset) {
+ /// `@callKind=closure` indicates that the receiver of the call is a function
+ /// object (so any formals marked as "semiSafe" will have to be type checked).
+ /// An annotation of `@callKind=this` indicates that the call goes through
+ /// `super` or `this` (so formals marked as "semiSafe" don't need to be type
+ /// checked). No annotation indicates that either the call is static, in
+ /// which case no parameters need to be type checked, or it goes through an
+ /// interface, in which case the set of arguments that have to be type checked
+ /// depends on the `@checkInterface` annotations on the static target of the
+ /// call.
+ void _annotateCallKind(Element staticElement, bool isThis, bool isDynamic,
+ DartType targetType, int offset) {
if (staticElement is FunctionElement &&
staticElement.enclosingElement is CompilationUnitElement) {
// Invocation of a top level function; no annotation needed.
@@ -212,55 +177,23 @@ class _InstrumentationVisitor extends GeneralizingAstVisitor<Null> {
// Sometimes analyzer annotates invocations of function objects as
// dynamic (presumably due to "dynamic is bottom" behavior). Ignore
// this.
+ _recordCallKind(offset, 'closure');
} else {
- _recordCheckCall(offset, 'dynamic');
+ _recordCallKind(offset, 'dynamic');
return;
}
}
- if (staticElement is MethodElement && isThis) {
- // Calls through "this" are always typed because the type parameters match
- // up perfectly; no annotation needed.
- return;
- }
- var semiTypedArgs = <String>[];
- if (typeArguments != null) {
- for (int argPosition = 0;
- argPosition < typeArguments.length;
- argPosition++) {
- DartType getArgument(FunctionType functionType) {
- return functionType.typeFormals[argPosition].bound;
- }
-
- if (_isArgumentSemiTyped(targetType, staticElement, getArgument)) {
- semiTypedArgs.add('<$argPosition>');
- }
- }
- }
- int argPosition = 0;
- for (var argument in arguments) {
- assert(argument is! NamedExpression); // TODO(paulberry): handle this
- DartType getArgument(FunctionType functionType) {
- // TODO(paulberry): handle named parameters
- if (argPosition >= functionType.normalParameterTypes.length) {
- return functionType.optionalParameterTypes[
- argPosition - functionType.normalParameterTypes.length];
- } else {
- return functionType.normalParameterTypes[argPosition];
- }
- }
-
- if (_isArgumentSemiTyped(targetType, staticElement, getArgument)) {
- semiTypedArgs.add('$argPosition');
+ if (staticElement is MethodElement && !staticElement.isStatic ||
+ staticElement is PropertyAccessorElement && !staticElement.isStatic) {
+ if (isThis) {
+ _recordCallKind(offset, 'this');
+ return;
+ } else {
+ // Interface call; no annotation needed
+ return;
}
- ++argPosition;
- }
- if (semiTypedArgs.isEmpty) {
- // We don't annotate invocations where all arguments are typed because
- // that's the common case.
- } else {
- _recordCheckCall(
- offset, 'interface(semiTyped:${semiTypedArgs.join(',')})');
}
+ _recordCallKind(offset, 'closure');
}
/// Generates the appropriate `@checkReturn` annotation (if any) for a call
@@ -275,21 +208,24 @@ class _InstrumentationVisitor extends GeneralizingAstVisitor<Null> {
}
}
- /// Generates the appropriate `@checkFormal` annotation (if any) for a method
- /// formal parameter, method type parameter, or field declaration.
+ /// Generates the appropriate `@checkFormal` and `@checkInterface` annotations
+ /// (if any) for a method formal parameter, method type parameter, or field
+ /// declaration.
///
- /// When this annotation is generated for a field declaration, it implicitly
- /// refers to the value parameter of the synthetic setter.
+ /// When these annotations are generated for a field declaration, they
+ /// implicitly refer to the value parameter of the synthetic setter.
///
/// An annotation of `@checkFormal=unsafe` indicates that the parameter needs
/// to be type checked regardless of the call site.
///
/// An annotation of `@checkFormal=semiSafe` indicates that the parameter
- /// needs to be type checked when corresponding argument at the call site is
- /// considered "semi-typed".
+ /// needs to be type checked when the call site is annotated
+ /// `@callKind=dynamic` or `@callKind=closure`, or the call site is
+ /// unannotated and the corresponding parameter in the interface target is
+ /// annotated `@checkInterface=semiTyped`.
///
- /// No annotation indicates that the parameter only needs to be type checked
- /// if the call site is a dynamic invocation.
+ /// No `@checkFormal` annotation indicates that the parameter only needs to be
+ /// type checked if the call site is annotated `@callKind=dynamic`.
void _annotateFormalParameter(
Element element, int offset, ClassDeclaration cls) {
if (element is ParameterElement && element.isCovariant) {
@@ -300,6 +236,19 @@ class _InstrumentationVisitor extends GeneralizingAstVisitor<Null> {
_recordCheckFormal(offset, 'semiSafe');
}
}
+ if (cls?.typeParameters != null) {
+ if (element is ParameterElement) {
+ if (_isFormalSemiTyped(
+ cls.typeParameters.typeParameters, element.type)) {
+ _recordCheckInterface(offset, 'semiTyped');
+ }
+ } else if (element is TypeParameterElement && element.bound != null) {
+ if (_isFormalSemiTyped(
+ cls.typeParameters.typeParameters, element.bound)) {
+ _recordCheckInterface(offset, 'semiTyped');
+ }
+ }
+ }
}
/// Generates the appropriate `@checkTearOff` annotation (if any) for a call
@@ -354,62 +303,31 @@ class _InstrumentationVisitor extends GeneralizingAstVisitor<Null> {
}
}
- /// Determines whether an argument at a call site should be considered
+ /// Determines whether a method formal parameter should be considered
/// "semi-typed".
///
- /// [targetType] indicates the type of the interface being invoked.
+ /// [typeParameters] is the list of type parameters of the enclosing class.
///
- /// [invocationTarget] is the method or getter/setter being invoked.
- ///
- /// [getArgument] is a callback for accessing the corresponding argument type
- /// from a [FunctionType].
- bool _isArgumentSemiTyped(InterfaceType targetType, Element invocationTarget,
- DartType getArgument(FunctionType functionType)) {
- bool _checkTypes(DartType originalArgumentType,
- DartType lookupArgumentType(InterfaceType interfaceType)) {
- // If the target type lacks type parameters, then everything is safe.
- if (targetType.typeParameters.isEmpty) return false;
-
- // To see if this argument needs to be semi-typed, we try substituting
- // bottom in for all the active type parameters. If the resulting
- // argument static type is a supertype of its current static type, then
- // that means that regardless of what we pass in, it won't fail a type
- // check.
- var substitutedInterfaceType = targetType.element.type.instantiate(
- new List<DartType>.filled(
- targetType.typeParameters.length, BottomTypeImpl.instance));
- var substitutedArgumentType =
- lookupArgumentType(substitutedInterfaceType);
- return !_typeSystem.isSubtypeOf(
- originalArgumentType, substitutedArgumentType);
- }
-
- if (invocationTarget is LocalVariableElement || invocationTarget == null) {
- // This is an invocation of a closure, so every argument is semi-typed.
- return true;
- } else if (invocationTarget is PropertyAccessorElement &&
- invocationTarget.isSetter) {
- return _checkTypes(
- invocationTarget.parameters[0].type,
- (InterfaceType type) => type
- .lookUpSetter(invocationTarget.name, invocationTarget.library)
- .parameters[0]
- .type);
- } else if (invocationTarget is MethodElement) {
- return _checkTypes(
- getArgument(invocationTarget.type),
- (InterfaceType type) => getArgument(type
- .lookUpMethod(invocationTarget.name, invocationTarget.library)
- .type));
- } else {
- throw new UnimplementedError(
- 'Unexpected invocation target type: ${invocationTarget.runtimeType}');
- }
+ /// [formalType] is the type of the formal parameter (or the type bound, if
+ /// we are looking at a type parameter of a generic method).
+ bool _isFormalSemiTyped(
+ List<TypeParameter> typeParameters, DartType formalType) {
+ // To see if this parameter needs to be semi-typed, we try substituting
+ // bottom for all the active type parameters. If the resulting parameter
+ // static type is a supertype of its current static type, then that means
+ // that regardless of what we pass in, it won't fail a type check.
+ var substitutedType = formalType.substitute2(
+ new List<DartType>.filled(
+ typeParameters.length, BottomTypeImpl.instance),
+ typeParameters
+ .map((p) => new TypeParameterTypeImpl(p.element))
+ .toList());
+ return !_typeSystem.isSubtypeOf(formalType, substitutedType);
}
- void _recordCheckCall(int offset, String safety) {
- _instrumentation.record(uri, offset, 'checkCall',
- new fasta.InstrumentationValueLiteral(safety));
+ void _recordCallKind(int offset, String kind) {
+ _instrumentation.record(
+ uri, offset, 'callKind', new fasta.InstrumentationValueLiteral(kind));
}
void _recordCheckFormal(int offset, String safety) {
@@ -417,6 +335,11 @@ class _InstrumentationVisitor extends GeneralizingAstVisitor<Null> {
new fasta.InstrumentationValueLiteral(safety));
}
+ void _recordCheckInterface(int offset, String safety) {
+ _instrumentation.record(uri, offset, 'checkInterface',
+ new fasta.InstrumentationValueLiteral(safety));
+ }
+
void _recordCheckReturn(int offset, DartType castType) {
_instrumentation.record(uri, offset, 'checkReturn',
new InstrumentationValueForType(castType, _elementNamer));
« no previous file with comments | « no previous file | pkg/front_end/lib/src/fasta/testing/validating_instrumentation.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698