mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:49:47 +00:00
Add --no-declaration-casts option to analyzer.
Adds a flag to disable and enable declaration casts independently from other casts. Fixes #29546 BUG= R=brianwilkerson@google.com, rnystrom@google.com Review-Url: https://codereview.chromium.org/2976963002 .
This commit is contained in:
parent
203955bc48
commit
1eb480d266
|
@ -17,6 +17,7 @@ import 'package:path/path.dart';
|
|||
const String analysisOptionsFileOption = 'options';
|
||||
const String bazelAnalysisOptionsPath =
|
||||
'package:dart.analysis_options/default.yaml';
|
||||
const String declarationCastsFlag = 'declaration-casts';
|
||||
const String defineVariableOption = 'D';
|
||||
const String enableInitializingFormalAccessFlag = 'initializing-formal-access';
|
||||
const String enableStrictCallChecksFlag = 'enable-strict-call-checks';
|
||||
|
@ -24,8 +25,8 @@ const String enableSuperMixinFlag = 'supermixin';
|
|||
const String flutterAnalysisOptionsPath =
|
||||
'package:flutter/analysis_options_user.yaml';
|
||||
const String ignoreUnrecognizedFlagsFlag = 'ignore-unrecognized-flags';
|
||||
const String implicitCastsFlag = 'implicit-casts';
|
||||
const String lintsFlag = 'lints';
|
||||
const String noImplicitCastsFlag = 'no-implicit-casts';
|
||||
const String noImplicitDynamicFlag = 'no-implicit-dynamic';
|
||||
const String packageDefaultAnalysisOptions = 'package-default-analysis-options';
|
||||
const String packageRootOption = 'package-root';
|
||||
|
@ -54,9 +55,16 @@ void applyAnalysisOptionFlags(AnalysisOptionsImpl options, ArgResults args,
|
|||
options.enableSuperMixins = args[enableSuperMixinFlag];
|
||||
verbose('$enableSuperMixinFlag = ${options.enableSuperMixins}');
|
||||
}
|
||||
if (args.wasParsed(noImplicitCastsFlag)) {
|
||||
options.implicitCasts = !args[noImplicitCastsFlag];
|
||||
verbose('$noImplicitCastsFlag = ${options.implicitCasts}');
|
||||
if (args.wasParsed(implicitCastsFlag)) {
|
||||
options.implicitCasts = args[implicitCastsFlag];
|
||||
verbose('$implicitCastsFlag = ${options.implicitCasts}');
|
||||
}
|
||||
if (args.wasParsed(declarationCastsFlag)) {
|
||||
options.declarationCasts = args[declarationCastsFlag];
|
||||
verbose('$declarationCastsFlag = ${options.declarationCasts}');
|
||||
} else if (args.wasParsed(implicitCastsFlag)) {
|
||||
options.declarationCasts = args[implicitCastsFlag];
|
||||
verbose('$declarationCastsFlag = ${options.declarationCasts}');
|
||||
}
|
||||
if (args.wasParsed(noImplicitDynamicFlag)) {
|
||||
options.implicitDynamic = !args[noImplicitDynamicFlag];
|
||||
|
@ -174,8 +182,12 @@ void defineAnalysisArguments(ArgParser parser, {bool hide: true, ddc: false}) {
|
|||
parser.addFlag(strongModeFlag,
|
||||
help: 'Enable strong static checks (https://goo.gl/DqcBsw).',
|
||||
defaultsTo: ddc);
|
||||
parser.addFlag(noImplicitCastsFlag,
|
||||
negatable: false,
|
||||
parser.addFlag(declarationCastsFlag,
|
||||
negatable: true,
|
||||
help:
|
||||
'Disable declaration casts in strong mode (https://goo.gl/cTLz40).');
|
||||
parser.addFlag(implicitCastsFlag,
|
||||
negatable: true,
|
||||
help: 'Disable implicit casts in strong mode (https://goo.gl/cTLz40).');
|
||||
parser.addFlag(noImplicitDynamicFlag,
|
||||
negatable: false,
|
||||
|
|
|
@ -284,6 +284,9 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
|||
((options is AnalysisOptionsImpl)
|
||||
? this._options.strongModeHints != options.strongModeHints
|
||||
: false) ||
|
||||
((options is AnalysisOptionsImpl)
|
||||
? this._options.declarationCasts != options.declarationCasts
|
||||
: false) ||
|
||||
((options is AnalysisOptionsImpl)
|
||||
? this._options.implicitCasts != options.implicitCasts
|
||||
: false) ||
|
||||
|
@ -323,6 +326,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
|||
this._options.patchPaths = options.patchPaths;
|
||||
if (options is AnalysisOptionsImpl) {
|
||||
this._options.strongModeHints = options.strongModeHints;
|
||||
this._options.declarationCasts = options.declarationCasts;
|
||||
this._options.implicitCasts = options.implicitCasts;
|
||||
this._options.nonnullableTypes = options.nonnullableTypes;
|
||||
this._options.implicitDynamic = options.implicitDynamic;
|
||||
|
|
|
@ -272,6 +272,7 @@ class LibraryAnalyzer {
|
|||
_typeProvider,
|
||||
new StrongTypeSystemImpl(_typeProvider,
|
||||
implicitCasts: options.implicitCasts,
|
||||
declarationCasts: options.declarationCasts,
|
||||
nonnullableTypes: options.nonnullableTypes),
|
||||
errorListener,
|
||||
options);
|
||||
|
|
|
@ -1361,6 +1361,14 @@ class AnalysisOptionsImpl implements AnalysisOptions {
|
|||
*/
|
||||
Uint32List _signature;
|
||||
|
||||
/**
|
||||
* A flag indicating whether declaration casts are allowed in [strongMode]
|
||||
* (they are always allowed in Dart 1.0 mode).
|
||||
*
|
||||
* This option is experimental and subject to change.
|
||||
*/
|
||||
bool declarationCasts = true;
|
||||
|
||||
@override
|
||||
@deprecated
|
||||
int cacheSize = 64;
|
||||
|
@ -1491,6 +1499,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
|
|||
preserveComments = options.preserveComments;
|
||||
strongMode = options.strongMode;
|
||||
if (options is AnalysisOptionsImpl) {
|
||||
declarationCasts = options.declarationCasts;
|
||||
strongModeHints = options.strongModeHints;
|
||||
implicitCasts = options.implicitCasts;
|
||||
nonnullableTypes = options.nonnullableTypes;
|
||||
|
@ -1607,6 +1616,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
|
|||
ApiSignature buffer = new ApiSignature();
|
||||
|
||||
// Append boolean flags.
|
||||
buffer.addBool(declarationCasts);
|
||||
buffer.addBool(enableAssertInitializer);
|
||||
buffer.addBool(enableLazyAssignmentOperators);
|
||||
buffer.addBool(enableStrictCallChecks);
|
||||
|
@ -1638,6 +1648,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
|
|||
|
||||
@override
|
||||
void resetToDefaults() {
|
||||
declarationCasts = true;
|
||||
dart2jsHint = false;
|
||||
disableCacheFlushing = false;
|
||||
enableAssertInitializer = false;
|
||||
|
|
|
@ -1205,7 +1205,8 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
|||
SimpleIdentifier nameNode = node.name;
|
||||
Expression initializerNode = node.initializer;
|
||||
// do checks
|
||||
_checkForInvalidAssignment(nameNode, initializerNode);
|
||||
_checkForInvalidAssignment(nameNode, initializerNode,
|
||||
isDeclarationCast: true);
|
||||
_checkForImplicitDynamicIdentifier(node, nameNode);
|
||||
// visit name
|
||||
nameNode.accept(this);
|
||||
|
@ -2504,20 +2505,24 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
|||
}
|
||||
|
||||
bool _checkForAssignableExpression(
|
||||
Expression expression, DartType expectedStaticType, ErrorCode errorCode) {
|
||||
Expression expression, DartType expectedStaticType, ErrorCode errorCode,
|
||||
{bool isDeclarationCast = false}) {
|
||||
DartType actualStaticType = getStaticType(expression);
|
||||
return actualStaticType != null &&
|
||||
_checkForAssignableExpressionAtType(
|
||||
expression, actualStaticType, expectedStaticType, errorCode);
|
||||
expression, actualStaticType, expectedStaticType, errorCode,
|
||||
isDeclarationCast: isDeclarationCast);
|
||||
}
|
||||
|
||||
bool _checkForAssignableExpressionAtType(
|
||||
Expression expression,
|
||||
DartType actualStaticType,
|
||||
DartType expectedStaticType,
|
||||
ErrorCode errorCode) {
|
||||
ErrorCode errorCode,
|
||||
{bool isDeclarationCast = false}) {
|
||||
if (!_expressionIsAssignableAtType(
|
||||
expression, actualStaticType, expectedStaticType)) {
|
||||
expression, actualStaticType, expectedStaticType,
|
||||
isDeclarationCast: isDeclarationCast)) {
|
||||
_errorReporter.reportTypeErrorForNode(
|
||||
errorCode, expression, [actualStaticType, expectedStaticType]);
|
||||
return false;
|
||||
|
@ -4272,7 +4277,8 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
|||
StaticTypeWarningCode.FOR_IN_OF_INVALID_TYPE,
|
||||
node.iterable,
|
||||
[iterableType, loopTypeName]);
|
||||
} else if (!_typeSystem.isAssignableTo(bestIterableType, variableType)) {
|
||||
} else if (!_typeSystem.isAssignableTo(bestIterableType, variableType,
|
||||
isDeclarationCast: true)) {
|
||||
_errorReporter.reportTypeErrorForNode(
|
||||
StaticTypeWarningCode.FOR_IN_OF_INVALID_ELEMENT_TYPE,
|
||||
node.iterable,
|
||||
|
@ -4426,7 +4432,8 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
|||
*
|
||||
* See [StaticTypeWarningCode.INVALID_ASSIGNMENT].
|
||||
*/
|
||||
void _checkForInvalidAssignment(Expression lhs, Expression rhs) {
|
||||
void _checkForInvalidAssignment(Expression lhs, Expression rhs,
|
||||
{bool isDeclarationCast = false}) {
|
||||
if (lhs == null || rhs == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -4435,7 +4442,8 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
|||
? getStaticType(lhs)
|
||||
: leftVariableElement.type;
|
||||
_checkForAssignableExpression(
|
||||
rhs, leftType, StaticTypeWarningCode.INVALID_ASSIGNMENT);
|
||||
rhs, leftType, StaticTypeWarningCode.INVALID_ASSIGNMENT,
|
||||
isDeclarationCast: isDeclarationCast);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6318,13 +6326,15 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
|||
}
|
||||
|
||||
bool _expressionIsAssignableAtType(Expression expression,
|
||||
DartType actualStaticType, DartType expectedStaticType) {
|
||||
DartType actualStaticType, DartType expectedStaticType,
|
||||
{isDeclarationCast: false}) {
|
||||
bool concrete = _options.strongMode && checker.hasStrictArrow(expression);
|
||||
if (concrete && actualStaticType is FunctionType) {
|
||||
actualStaticType =
|
||||
_typeSystem.functionTypeToConcreteType(actualStaticType);
|
||||
}
|
||||
return _typeSystem.isAssignableTo(actualStaticType, expectedStaticType);
|
||||
return _typeSystem.isAssignableTo(actualStaticType, expectedStaticType,
|
||||
isDeclarationCast: isDeclarationCast);
|
||||
}
|
||||
|
||||
MethodElement _findOverriddenMemberThatMustCallSuper(MethodDeclaration node) {
|
||||
|
|
|
@ -847,14 +847,16 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
|
|||
? ErrorVerifier.getStaticType(lhs)
|
||||
: leftVariableElement.type;
|
||||
DartType staticRightType = ErrorVerifier.getStaticType(rhs);
|
||||
if (!_typeSystem.isAssignableTo(staticRightType, leftType)) {
|
||||
if (!_typeSystem.isAssignableTo(staticRightType, leftType,
|
||||
isDeclarationCast: true)) {
|
||||
// The warning was generated on this rhs
|
||||
return false;
|
||||
}
|
||||
// Test for, and then generate the hint
|
||||
DartType bestRightType = rhs.bestType;
|
||||
if (leftType != null && bestRightType != null) {
|
||||
if (!_typeSystem.isAssignableTo(bestRightType, leftType)) {
|
||||
if (!_typeSystem.isAssignableTo(bestRightType, leftType,
|
||||
isDeclarationCast: true)) {
|
||||
_errorReporter.reportTypeErrorForNode(
|
||||
HintCode.INVALID_ASSIGNMENT, rhs, [bestRightType, leftType]);
|
||||
return true;
|
||||
|
|
|
@ -47,6 +47,13 @@ typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<TypeImpl> visitedTypes);
|
|||
class StrongTypeSystemImpl extends TypeSystem {
|
||||
static bool _comparingTypeParameterBounds = false;
|
||||
|
||||
/**
|
||||
* True if declaration casts should be allowed, otherwise false.
|
||||
*
|
||||
* This affects the behavior of [isAssignableTo].
|
||||
*/
|
||||
final bool declarationCasts;
|
||||
|
||||
/**
|
||||
* True if implicit casts should be allowed, otherwise false.
|
||||
*
|
||||
|
@ -62,7 +69,8 @@ class StrongTypeSystemImpl extends TypeSystem {
|
|||
final TypeProvider typeProvider;
|
||||
|
||||
StrongTypeSystemImpl(this.typeProvider,
|
||||
{this.implicitCasts: true,
|
||||
{this.declarationCasts: true,
|
||||
this.implicitCasts: true,
|
||||
this.nonnullableTypes: AnalysisOptionsImpl.NONNULLABLE_TYPES});
|
||||
|
||||
@override
|
||||
|
@ -409,7 +417,8 @@ class StrongTypeSystemImpl extends TypeSystem {
|
|||
}
|
||||
|
||||
@override
|
||||
bool isAssignableTo(DartType fromType, DartType toType) {
|
||||
bool isAssignableTo(DartType fromType, DartType toType,
|
||||
{bool isDeclarationCast = false}) {
|
||||
// TODO(leafp): Document the rules in play here
|
||||
|
||||
// An actual subtype
|
||||
|
@ -417,7 +426,11 @@ class StrongTypeSystemImpl extends TypeSystem {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!implicitCasts) {
|
||||
if (isDeclarationCast) {
|
||||
if (!declarationCasts) {
|
||||
return false;
|
||||
}
|
||||
} else if (!implicitCasts) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1222,7 +1235,8 @@ abstract class TypeSystem {
|
|||
* Return `true` if the [leftType] is assignable to the [rightType] (that is,
|
||||
* if leftType <==> rightType).
|
||||
*/
|
||||
bool isAssignableTo(DartType leftType, DartType rightType);
|
||||
bool isAssignableTo(DartType leftType, DartType rightType,
|
||||
{bool isDeclarationCast = false});
|
||||
|
||||
/**
|
||||
* Return `true` if the [leftType] is more specific than the [rightType]
|
||||
|
@ -1476,6 +1490,7 @@ abstract class TypeSystem {
|
|||
var options = context.analysisOptions as AnalysisOptionsImpl;
|
||||
return options.strongMode
|
||||
? new StrongTypeSystemImpl(context.typeProvider,
|
||||
declarationCasts: options.declarationCasts,
|
||||
implicitCasts: options.implicitCasts,
|
||||
nonnullableTypes: options.nonnullableTypes)
|
||||
: new TypeSystemImpl(context.typeProvider);
|
||||
|
@ -1511,7 +1526,8 @@ class TypeSystemImpl extends TypeSystem {
|
|||
}
|
||||
|
||||
@override
|
||||
bool isAssignableTo(DartType leftType, DartType rightType) {
|
||||
bool isAssignableTo(DartType leftType, DartType rightType,
|
||||
{bool isDeclarationCast = false}) {
|
||||
return leftType.isAssignableTo(rightType);
|
||||
}
|
||||
|
||||
|
|
|
@ -5490,6 +5490,7 @@ class StrongModeVerifyUnitTask extends SourceBasedAnalysisTask {
|
|||
typeProvider,
|
||||
new StrongTypeSystemImpl(typeProvider,
|
||||
implicitCasts: options.implicitCasts,
|
||||
declarationCasts: options.declarationCasts,
|
||||
nonnullableTypes: options.nonnullableTypes),
|
||||
errorListener,
|
||||
options);
|
||||
|
|
|
@ -58,6 +58,7 @@ class AnalyzerOptions {
|
|||
static const String strong_mode = 'strong-mode';
|
||||
|
||||
// Strong mode options, see AnalysisOptionsImpl for documentation.
|
||||
static const String declarationCasts = 'declaration-casts';
|
||||
static const String implicitCasts = 'implicit-casts';
|
||||
static const String implicitDynamic = 'implicit-dynamic';
|
||||
|
||||
|
@ -573,6 +574,9 @@ class _OptionsProcessor {
|
|||
AnalysisOptionsImpl options, Object feature, Object value) {
|
||||
bool boolValue = toBool(value);
|
||||
if (boolValue != null) {
|
||||
if (feature == AnalyzerOptions.declarationCasts) {
|
||||
options.declarationCasts = boolValue;
|
||||
}
|
||||
if (feature == AnalyzerOptions.implicitCasts) {
|
||||
options.implicitCasts = boolValue;
|
||||
}
|
||||
|
|
|
@ -197,10 +197,19 @@ class CodeChecker extends RecursiveAstVisitor {
|
|||
}
|
||||
|
||||
void checkAssignment(Expression expr, DartType type) {
|
||||
checkForCast(expr, type);
|
||||
}
|
||||
|
||||
void checkDeclarationCast(Expression expr, DartType type) {
|
||||
checkForCast(expr, type, isDeclarationCast: true);
|
||||
}
|
||||
|
||||
void checkForCast(Expression expr, DartType type,
|
||||
{bool isDeclarationCast = false}) {
|
||||
if (expr is ParenthesizedExpression) {
|
||||
checkAssignment(expr.expression, type);
|
||||
checkForCast(expr.expression, type);
|
||||
} else {
|
||||
_checkImplicitCast(expr, type);
|
||||
_checkImplicitCast(expr, type, isDeclarationCast: isDeclarationCast);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -432,7 +441,7 @@ class CodeChecker extends RecursiveAstVisitor {
|
|||
// Insert a cast from the sequence's element type to the loop variable's
|
||||
// if needed.
|
||||
_checkImplicitCast(loopVariable, _getDefiniteType(loopVariable),
|
||||
from: elementType);
|
||||
from: elementType, isDeclarationCast: true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -684,7 +693,7 @@ class CodeChecker extends RecursiveAstVisitor {
|
|||
var initializer = variable.initializer;
|
||||
if (initializer != null) {
|
||||
if (type != null) {
|
||||
checkAssignment(initializer, type.type);
|
||||
checkDeclarationCast(initializer, type.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -760,10 +769,12 @@ class CodeChecker extends RecursiveAstVisitor {
|
|||
/// If [expr] does not require an implicit cast because it is not related to
|
||||
/// [to] or is already a subtype of it, does nothing.
|
||||
void _checkImplicitCast(Expression expr, DartType to,
|
||||
{DartType from, bool opAssign: false}) {
|
||||
{DartType from, bool opAssign: false, bool isDeclarationCast: false}) {
|
||||
from ??= _getDefiniteType(expr);
|
||||
|
||||
if (_needsImplicitCast(expr, to, from: from) == true) {
|
||||
if (_needsImplicitCast(expr, to,
|
||||
from: from, isDeclarationCast: isDeclarationCast) ==
|
||||
true) {
|
||||
_recordImplicitCast(expr, to, from: from, opAssign: opAssign);
|
||||
}
|
||||
}
|
||||
|
@ -1062,7 +1073,8 @@ class CodeChecker extends RecursiveAstVisitor {
|
|||
/// types are statically incompatible.
|
||||
///
|
||||
/// If [from] is omitted, uses the static type of [expr]
|
||||
bool _needsImplicitCast(Expression expr, DartType to, {DartType from}) {
|
||||
bool _needsImplicitCast(Expression expr, DartType to,
|
||||
{DartType from, bool isDeclarationCast: false}) {
|
||||
from ??= _getDefiniteType(expr);
|
||||
|
||||
if (!_checkNonNullAssignment(expr, to, from)) return false;
|
||||
|
@ -1074,7 +1086,8 @@ class CodeChecker extends RecursiveAstVisitor {
|
|||
if (rules.isSubtypeOf(from, to)) return false;
|
||||
|
||||
// Down cast or legal sideways cast, coercion needed.
|
||||
if (rules.isAssignableTo(from, to)) return true;
|
||||
if (rules.isAssignableTo(from, to, isDeclarationCast: isDeclarationCast))
|
||||
return true;
|
||||
|
||||
// Special case for FutureOr to handle returned values from async functions.
|
||||
// In this case, we're more permissive than assignability.
|
||||
|
|
|
@ -35,6 +35,7 @@ class ArgumentsTest {
|
|||
'-Dfoo=1',
|
||||
'-Dbar=2',
|
||||
'--enable-strict-call-checks',
|
||||
'--no-declaration-casts',
|
||||
'--no-implicit-casts',
|
||||
'--no-implicit-dynamic',
|
||||
'--options=$defaultAnalysisOptionsFilePath',
|
||||
|
@ -59,6 +60,7 @@ class ArgumentsTest {
|
|||
expect(defaultOptions, isNotNull);
|
||||
expect(defaultOptions.enableStrictCallChecks, true);
|
||||
expect(defaultOptions.strongMode, true);
|
||||
expect(defaultOptions.declarationCasts, false);
|
||||
expect(defaultOptions.implicitCasts, false);
|
||||
expect(defaultOptions.implicitDynamic, false);
|
||||
}
|
||||
|
@ -80,6 +82,7 @@ class ArgumentsTest {
|
|||
expect(defaultOptions, isNotNull);
|
||||
expect(defaultOptions.enableStrictCallChecks, false);
|
||||
expect(defaultOptions.strongMode, false);
|
||||
expect(defaultOptions.declarationCasts, true);
|
||||
expect(defaultOptions.implicitCasts, true);
|
||||
expect(defaultOptions.implicitDynamic, true);
|
||||
}
|
||||
|
@ -134,10 +137,27 @@ class ArgumentsTest {
|
|||
expect(manager.canUseSummaries, true);
|
||||
}
|
||||
|
||||
void test_declarationCast_noImplicitCast() {
|
||||
MemoryResourceProvider provider = new MemoryResourceProvider();
|
||||
ArgParser parser = new ArgParser();
|
||||
defineAnalysisArguments(parser);
|
||||
List<String> args = [
|
||||
'--declaration-casts',
|
||||
'--no-implicit-casts',
|
||||
];
|
||||
ArgResults result = parse(provider, parser, args);
|
||||
ContextBuilderOptions options = createContextBuilderOptions(result);
|
||||
expect(options, isNotNull);
|
||||
AnalysisOptionsImpl defaultOptions = options.defaultOptions;
|
||||
expect(defaultOptions, isNotNull);
|
||||
expect(defaultOptions.declarationCasts, true);
|
||||
expect(defaultOptions.implicitCasts, false);
|
||||
}
|
||||
|
||||
void test_defineAnalysisArguments() {
|
||||
ArgParser parser = new ArgParser();
|
||||
defineAnalysisArguments(parser);
|
||||
expect(parser.options, hasLength(14));
|
||||
expect(parser.options, hasLength(15));
|
||||
}
|
||||
|
||||
void test_extractDefinedVariables() {
|
||||
|
@ -166,6 +186,55 @@ class ArgumentsTest {
|
|||
expect(result, orderedEquals(['--a', '--c=0', '-e=2', '-f', 'bar']));
|
||||
}
|
||||
|
||||
void test_noAssignmentCast() {
|
||||
MemoryResourceProvider provider = new MemoryResourceProvider();
|
||||
ArgParser parser = new ArgParser();
|
||||
defineAnalysisArguments(parser);
|
||||
List<String> args = [
|
||||
'--no-declaration-casts',
|
||||
];
|
||||
ArgResults result = parse(provider, parser, args);
|
||||
ContextBuilderOptions options = createContextBuilderOptions(result);
|
||||
expect(options, isNotNull);
|
||||
AnalysisOptionsImpl defaultOptions = options.defaultOptions;
|
||||
expect(defaultOptions, isNotNull);
|
||||
expect(defaultOptions.declarationCasts, false);
|
||||
expect(defaultOptions.implicitCasts, true);
|
||||
}
|
||||
|
||||
void test_noAssignmentCast_implicitCast() {
|
||||
MemoryResourceProvider provider = new MemoryResourceProvider();
|
||||
ArgParser parser = new ArgParser();
|
||||
defineAnalysisArguments(parser);
|
||||
List<String> args = [
|
||||
'--no-declaration-casts',
|
||||
'--implicit-casts',
|
||||
];
|
||||
ArgResults result = parse(provider, parser, args);
|
||||
ContextBuilderOptions options = createContextBuilderOptions(result);
|
||||
expect(options, isNotNull);
|
||||
AnalysisOptionsImpl defaultOptions = options.defaultOptions;
|
||||
expect(defaultOptions, isNotNull);
|
||||
expect(defaultOptions.declarationCasts, false);
|
||||
expect(defaultOptions.implicitCasts, true);
|
||||
}
|
||||
|
||||
void test_noImplicitCast() {
|
||||
MemoryResourceProvider provider = new MemoryResourceProvider();
|
||||
ArgParser parser = new ArgParser();
|
||||
defineAnalysisArguments(parser);
|
||||
List<String> args = [
|
||||
'--no-implicit-casts',
|
||||
];
|
||||
ArgResults result = parse(provider, parser, args);
|
||||
ContextBuilderOptions options = createContextBuilderOptions(result);
|
||||
expect(options, isNotNull);
|
||||
AnalysisOptionsImpl defaultOptions = options.defaultOptions;
|
||||
expect(defaultOptions, isNotNull);
|
||||
expect(defaultOptions.declarationCasts, false);
|
||||
expect(defaultOptions.implicitCasts, false);
|
||||
}
|
||||
|
||||
void test_parse_noReplacement_noIgnored() {
|
||||
MemoryResourceProvider provider = new MemoryResourceProvider();
|
||||
ArgParser parser = new ArgParser();
|
||||
|
|
|
@ -1014,6 +1014,7 @@ linter:
|
|||
expect(actual.preserveComments, expected.preserveComments);
|
||||
expect(actual.strongMode, expected.strongMode);
|
||||
expect(actual.strongModeHints, expected.strongModeHints);
|
||||
expect(actual.declarationCasts, expected.declarationCasts);
|
||||
expect(actual.implicitCasts, expected.implicitCasts);
|
||||
expect(actual.implicitDynamic, expected.implicitDynamic);
|
||||
expect(actual.trackCacheDependencies, expected.trackCacheDependencies);
|
||||
|
|
|
@ -2196,11 +2196,96 @@ main() {
|
|||
''');
|
||||
}
|
||||
|
||||
test_implicitCasts() async {
|
||||
addFile('num n; int i = /*info:ASSIGNMENT_CAST*/n;');
|
||||
test_implicitCasts_assignment() async {
|
||||
addFile(
|
||||
'num n; int i; void main() { i = /*info:DOWN_CAST_IMPLICIT*/n;}//yy');
|
||||
await check();
|
||||
addFile('num n; int i = /*error:INVALID_ASSIGNMENT*/n;');
|
||||
await check(implicitCasts: false);
|
||||
addFile(
|
||||
'num n; int i; void main() { i = /*error:INVALID_ASSIGNMENT*/n;}//ny');
|
||||
await check(implicitCasts: false, declarationCasts: true);
|
||||
addFile(
|
||||
'num n; int i; void main() { i = /*info:DOWN_CAST_IMPLICIT*/n;}//yn');
|
||||
await check(implicitCasts: true, declarationCasts: false);
|
||||
addFile(
|
||||
'num n; int i; void main() { i = /*error:INVALID_ASSIGNMENT*/n;}//nn');
|
||||
await check(implicitCasts: false, declarationCasts: false);
|
||||
}
|
||||
|
||||
test_implicitCasts_compoundAssignment() async {
|
||||
addFile('''f(num n, int i) {
|
||||
/*info:DOWN_CAST_IMPLICIT_ASSIGN*/i += n;}//yy''');
|
||||
await check();
|
||||
addFile('''f(num n, int i) {
|
||||
i += /*error:INVALID_ASSIGNMENT*/n;}//ny''');
|
||||
await check(implicitCasts: false, declarationCasts: true);
|
||||
addFile('''f(num n, int i) {
|
||||
/*info:DOWN_CAST_IMPLICIT_ASSIGN*/i += n;}//yn''');
|
||||
await check(implicitCasts: true, declarationCasts: false);
|
||||
addFile('''f(num n, int i) {
|
||||
i += /*error:INVALID_ASSIGNMENT*/n;}//nn''');
|
||||
await check(implicitCasts: false, declarationCasts: false);
|
||||
}
|
||||
|
||||
test_implicitCasts_constructorInitializer() async {
|
||||
addFile(
|
||||
'class A { int i; A(num n) : i = /*info:DOWN_CAST_IMPLICIT*/n;}//yy');
|
||||
await check();
|
||||
addFile(
|
||||
'class A { int i; A(num n) : i = /*error:FIELD_INITIALIZER_NOT_ASSIGNABLE*/n;}//ny');
|
||||
await check(implicitCasts: false, declarationCasts: true);
|
||||
addFile(
|
||||
'class A { int i; A(num n) : i = /*info:DOWN_CAST_IMPLICIT*/n;}//yn');
|
||||
await check(implicitCasts: true, declarationCasts: false);
|
||||
addFile(
|
||||
'class A { int i; A(num n) : i = /*error:FIELD_INITIALIZER_NOT_ASSIGNABLE*/n;}//nn');
|
||||
await check(implicitCasts: false, declarationCasts: false);
|
||||
}
|
||||
|
||||
test_implicitCasts_defaultValue() async {
|
||||
addFile('''const num n = 0;
|
||||
f({int i = /*info:DOWN_CAST_IMPLICIT*/n}) => i;//yy''');
|
||||
await check();
|
||||
addFile('''const num n = 0;
|
||||
f({int i = /*error:INVALID_ASSIGNMENT*/n}) => i;//ny''');
|
||||
await check(implicitCasts: false, declarationCasts: true);
|
||||
addFile('''const num n = 0;
|
||||
f({int i = /*info:DOWN_CAST_IMPLICIT*/n}) => i;//yn''');
|
||||
await check(implicitCasts: true, declarationCasts: false);
|
||||
addFile('''const num n = 0;
|
||||
f({int i = /*error:INVALID_ASSIGNMENT*/n}) => i;//nn''');
|
||||
await check(implicitCasts: false, declarationCasts: false);
|
||||
}
|
||||
|
||||
test_implicitCasts_fieldInitializer() async {
|
||||
addFile('class A { static num n; int i = /*info:ASSIGNMENT_CAST*/n;}//yy');
|
||||
await check();
|
||||
addFile('class A { static num n; int i = /*info:ASSIGNMENT_CAST*/n;}//ny');
|
||||
await check(implicitCasts: false, declarationCasts: true);
|
||||
addFile(
|
||||
'class A { static num n; int i = /*error:INVALID_ASSIGNMENT*/n;}//yn');
|
||||
await check(implicitCasts: true, declarationCasts: false);
|
||||
addFile(
|
||||
'class A { static num n; int i = /*error:INVALID_ASSIGNMENT*/n;}//nn');
|
||||
await check(implicitCasts: false, declarationCasts: false);
|
||||
}
|
||||
|
||||
test_implicitCasts_functionCall() async {
|
||||
addFile('''num n;
|
||||
f(int i) => i;
|
||||
var i = f(/*info:DOWN_CAST_IMPLICIT*/n);//yy''');
|
||||
await check();
|
||||
addFile('''num n;
|
||||
f(int i) => i;
|
||||
var i = f(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/n);//ny''');
|
||||
await check(implicitCasts: false, declarationCasts: true);
|
||||
addFile('''num n;
|
||||
f(int i) => i;
|
||||
var i = f(/*info:DOWN_CAST_IMPLICIT*/n);//yn''');
|
||||
await check(implicitCasts: true, declarationCasts: false);
|
||||
addFile('''num n;
|
||||
f(int i) => i;
|
||||
var i = f(/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/n);//nn''');
|
||||
await check(implicitCasts: false, declarationCasts: false);
|
||||
}
|
||||
|
||||
test_implicitCasts_genericMethods() async {
|
||||
|
@ -2210,6 +2295,17 @@ var x = <String>[].map<String>((x) => "");
|
|||
await check(implicitCasts: false);
|
||||
}
|
||||
|
||||
test_implicitCasts_initializer() async {
|
||||
addFile('num n; int i = /*info:ASSIGNMENT_CAST*/n;//yy');
|
||||
await check();
|
||||
addFile('num n; int i = /*info:ASSIGNMENT_CAST*/n;//ny');
|
||||
await check(implicitCasts: false, declarationCasts: true);
|
||||
addFile('num n; int i = /*error:INVALID_ASSIGNMENT*/n;//yn');
|
||||
await check(implicitCasts: true, declarationCasts: false);
|
||||
addFile('num n; int i = /*error:INVALID_ASSIGNMENT*/n;//nn');
|
||||
await check(implicitCasts: false, declarationCasts: false);
|
||||
}
|
||||
|
||||
test_implicitCasts_numericOps() async {
|
||||
// Regression test for https://github.com/dart-lang/sdk/issues/26912
|
||||
addFile(r'''
|
||||
|
@ -2222,7 +2318,37 @@ void f() {
|
|||
await check(implicitCasts: false);
|
||||
}
|
||||
|
||||
test_implicitCasts_operator() async {
|
||||
addFile('''num n;
|
||||
int i;
|
||||
var r = i & /*info:DOWN_CAST_IMPLICIT*/n;//yy''');
|
||||
await check();
|
||||
addFile('''num n;
|
||||
int i;
|
||||
var r = i & /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/n;//ny''');
|
||||
await check(implicitCasts: false, declarationCasts: true);
|
||||
addFile('''num n;
|
||||
int i;
|
||||
var r = i & /*info:DOWN_CAST_IMPLICIT*/n;//yn''');
|
||||
await check(implicitCasts: true, declarationCasts: false);
|
||||
addFile('''num n;
|
||||
int i;
|
||||
var r = i & /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/n;//nn''');
|
||||
await check(implicitCasts: false, declarationCasts: false);
|
||||
}
|
||||
|
||||
test_implicitCasts_return() async {
|
||||
addFile('int f(num n) => /*info:DOWN_CAST_IMPLICIT*/n;//yy');
|
||||
await check();
|
||||
addFile('int f(num n) => /*error:RETURN_OF_INVALID_TYPE*/n;//ny');
|
||||
await check(implicitCasts: false, declarationCasts: true);
|
||||
addFile('int f(num n) => /*info:DOWN_CAST_IMPLICIT*/n;//yn');
|
||||
await check(implicitCasts: true, declarationCasts: false);
|
||||
addFile('int f(num n) => /*error:RETURN_OF_INVALID_TYPE*/n;//nn');
|
||||
await check(implicitCasts: false, declarationCasts: false);
|
||||
}
|
||||
|
||||
test_implicitCasts_return_async() async {
|
||||
addFile(r'''
|
||||
import 'dart:async';
|
||||
|
||||
|
|
|
@ -270,7 +270,8 @@ class AbstractStrongTest {
|
|||
///
|
||||
/// Returns the main resolved library. This can be used for further checks.
|
||||
Future<CompilationUnit> check(
|
||||
{bool implicitCasts: true,
|
||||
{bool declarationCasts: true,
|
||||
bool implicitCasts: true,
|
||||
bool implicitDynamic: true,
|
||||
List<String> nonnullableTypes:
|
||||
AnalysisOptionsImpl.NONNULLABLE_TYPES}) async {
|
||||
|
@ -283,6 +284,7 @@ class AbstractStrongTest {
|
|||
AnalysisOptionsImpl analysisOptions = new AnalysisOptionsImpl();
|
||||
analysisOptions.strongMode = true;
|
||||
analysisOptions.strongModeHints = true;
|
||||
analysisOptions.declarationCasts = declarationCasts;
|
||||
analysisOptions.implicitCasts = implicitCasts;
|
||||
analysisOptions.implicitDynamic = implicitDynamic;
|
||||
analysisOptions.nonnullableTypes = nonnullableTypes;
|
||||
|
|
|
@ -39,6 +39,9 @@ class CommandLineOptions {
|
|||
/// a constructor.
|
||||
final bool enableAssertInitializer;
|
||||
|
||||
/// Whether declaration casts are enabled (in strong mode)
|
||||
final bool declarationCasts;
|
||||
|
||||
/// The path to output analysis results when in build mode.
|
||||
final String buildAnalysisOutput;
|
||||
|
||||
|
@ -170,6 +173,9 @@ class CommandLineOptions {
|
|||
contextBuilderOptions = createContextBuilderOptions(args),
|
||||
dartSdkPath = args['dart-sdk'],
|
||||
dartSdkSummaryPath = args['dart-sdk-summary'],
|
||||
declarationCasts = args.wasParsed(declarationCastsFlag)
|
||||
? args[declarationCastsFlag]
|
||||
: args[implicitCastsFlag],
|
||||
disableCacheFlushing = args['disable-cache-flushing'],
|
||||
disableHints = args['no-hints'],
|
||||
displayVersion = args['version'],
|
||||
|
@ -191,7 +197,7 @@ class CommandLineOptions {
|
|||
warningsAreFatal = args['fatal-warnings'],
|
||||
lintsAreFatal = args['fatal-lints'],
|
||||
strongMode = args['strong'],
|
||||
implicitCasts = !args['no-implicit-casts'],
|
||||
implicitCasts = args[implicitCastsFlag],
|
||||
implicitDynamic = !args['no-implicit-dynamic'],
|
||||
useAnalysisDriverMemoryByteStore =
|
||||
args['use-analysis-driver-memory-byte-store'],
|
||||
|
|
Loading…
Reference in a new issue