blob: 48ccc75bf5fe9c1942dabeff98557f3028379c09 [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/test_utilities/package_mixin.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/driver_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(DeadCodeTest);
defineReflectiveTests(UncheckedUseOfNullableValueTest);
});
}
@reflectiveTest
class DeadCodeTest extends DriverResolutionTest with PackageMixin {
test_deadBlock_conditionalElse() async {
await assertErrorsInCode(r'''
f() {
true ? 1 : 2;
}''', [HintCode.DEAD_CODE]);
}
test_deadBlock_conditionalElse_nested() async {
// Test that a dead else-statement can't generate additional violations.
await assertErrorsInCode(r'''
f() {
true ? true : false && false;
}''', [HintCode.DEAD_CODE]);
}
test_deadBlock_conditionalIf() async {
await assertErrorsInCode(r'''
f() {
false ? 1 : 2;
}''', [HintCode.DEAD_CODE]);
}
test_deadBlock_conditionalIf_nested() async {
// Test that a dead then-statement can't generate additional violations.
await assertErrorsInCode(r'''
f() {
false ? false && false : true;
}''', [HintCode.DEAD_CODE]);
}
test_deadBlock_conditionalElse_debugConst() async {
await assertNoErrorsInCode(r'''
const bool DEBUG = true;
f() {
DEBUG ? 1 : 2;
}''');
}
test_deadBlock_conditionalIf_debugConst() async {
await assertNoErrorsInCode(r'''
const bool DEBUG = false;
f() {
DEBUG ? 1 : 2;
}''');
}
test_deadBlock_else() async {
await assertErrorsInCode(r'''
f() {
if(true) {} else {}
}''', [HintCode.DEAD_CODE]);
}
test_deadBlock_else_debugConst() async {
await assertNoErrorsInCode(r'''
const bool DEBUG = true;
f() {
if(DEBUG) {} else {}
}''');
}
test_deadBlock_if_debugConst_prefixedIdentifier() async {
await assertNoErrorsInCode(r'''
class A {
static const bool DEBUG = false;
}
f() {
if(A.DEBUG) {}
}''');
}
test_deadBlock_if_debugConst_prefixedIdentifier2() async {
newFile('/test/lib/lib2.dart', content: r'''
library lib2;
class A {
static const bool DEBUG = false;
}''');
await assertNoErrorsInCode(r'''
library L;
import 'lib2.dart';
f() {
if(A.DEBUG) {}
}''');
}
test_deadBlock_if_debugConst_propertyAccessor() async {
newFile('/test/lib/lib2.dart', content: r'''
library lib2;
class A {
static const bool DEBUG = false;
}''');
await assertNoErrorsInCode(r'''
library L;
import 'lib2.dart' as LIB;
f() {
if(LIB.A.DEBUG) {}
}''');
}
test_deadBlock_if_debugConst_simpleIdentifier() async {
await assertNoErrorsInCode(r'''
const bool DEBUG = false;
f() {
if(DEBUG) {}
}''');
}
test_deadBlock_else_nested() async {
// Test that a dead else-statement can't generate additional violations.
await assertErrorsInCode(r'''
f() {
if(true) {} else {if (false) {}}
}''', [HintCode.DEAD_CODE]);
}
test_deadBlock_if() async {
await assertErrorsInCode(r'''
f() {
if(false) {}
}''', [HintCode.DEAD_CODE]);
}
test_deadBlock_if_nested() async {
// Test that a dead then-statement can't generate additional violations.
await assertErrorsInCode(r'''
f() {
if(false) {if(false) {}}
}''', [HintCode.DEAD_CODE]);
}
test_deadBlock_while() async {
await assertErrorsInCode(r'''
f() {
while(false) {}
}''', [HintCode.DEAD_CODE]);
}
test_deadBlock_while_nested() async {
// Test that a dead while body can't generate additional violations.
await assertErrorsInCode(r'''
f() {
while(false) {if(false) {}}
}''', [HintCode.DEAD_CODE]);
}
test_deadBlock_while_debugConst() async {
await assertNoErrorsInCode(r'''
const bool DEBUG = false;
f() {
while(DEBUG) {}
}''');
}
test_deadCatch_catchFollowingCatch() async {
await assertErrorsInCode(r'''
class A {}
f() {
try {} catch (e) {} catch (e) {}
}''', [HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH]);
}
test_deadCatch_catchFollowingCatch_nested() async {
// Test that a dead catch clause can't generate additional violations.
await assertErrorsInCode(r'''
class A {}
f() {
try {} catch (e) {} catch (e) {if(false) {}}
}''', [HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH]);
}
test_deadCatch_catchFollowingCatch_object() async {
await assertErrorsInCode(r'''
f() {
try {} on Object catch (e) {} catch (e) {}
}''', [HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH]);
}
test_deadCatch_catchFollowingCatch_object_nested() async {
// Test that a dead catch clause can't generate additional violations.
await assertErrorsInCode(r'''
f() {
try {} on Object catch (e) {} catch (e) {if(false) {}}
}''', [HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH]);
}
test_deadCatch_onCatchSubtype() async {
await assertErrorsInCode(r'''
class A {}
class B extends A {}
f() {
try {} on A catch (e) {} on B catch (e) {}
}''', [HintCode.DEAD_CODE_ON_CATCH_SUBTYPE]);
}
test_deadCatch_onCatchSubtype_nested() async {
// Test that a dead catch clause can't generate additional violations.
await assertErrorsInCode(r'''
class A {}
class B extends A {}
f() {
try {} on A catch (e) {} on B catch (e) {if(false) {}}
}''', [HintCode.DEAD_CODE_ON_CATCH_SUBTYPE]);
}
test_deadCatch_onCatchSupertype() async {
await assertNoErrorsInCode(r'''
class A {}
class B extends A {}
f() {
try {} on B catch (e) {} on A catch (e) {} catch (e) {}
}''');
}
test_afterTryCatch() async {
await assertNoErrorsInCode(r'''
main() {
try {
return f();
} catch (e) {
print(e);
}
print('not dead');
}
f() {
throw 'foo';
}
''');
}
test_deadFinalReturnInCase() async {
await assertErrorsInCode(r'''
f() {
switch (true) {
case true:
try {
int a = 1;
} finally {
return;
}
return;
default:
break;
}
}''', [HintCode.DEAD_CODE]);
}
test_deadFinalStatementInCase() async {
await assertErrorsInCode(r'''
f() {
switch (true) {
case true:
try {
int a = 1;
} finally {
return;
}
throw 'msg';
default:
break;
}
}''', [HintCode.DEAD_CODE]);
}
test_deadFinalBreakInCase() async {
await assertNoErrorsInCode(r'''
f() {
switch (true) {
case true:
try {
int a = 1;
} finally {
return;
}
break;
default:
break;
}
}''');
}
test_deadOperandLHS_and() async {
await assertErrorsInCode(r'''
f() {
bool b = false && false;
}''', [HintCode.DEAD_CODE]);
}
test_deadOperandLHS_and_nested() async {
await assertErrorsInCode(r'''
f() {
bool b = false && (false && false);
}''', [HintCode.DEAD_CODE]);
}
test_deadOperandLHS_or() async {
await assertErrorsInCode(r'''
f() {
bool b = true || true;
}''', [HintCode.DEAD_CODE]);
}
test_deadOperandLHS_or_nested() async {
await assertErrorsInCode(r'''
f() {
bool b = true || (false && false);
}''', [HintCode.DEAD_CODE]);
}
test_deadOperandLHS_and_debugConst() async {
await assertNoErrorsInCode(r'''
const bool DEBUG = false;
f() {
bool b = DEBUG && false;
}''');
}
test_deadOperandLHS_or_debugConst() async {
await assertNoErrorsInCode(r'''
const bool DEBUG = true;
f() {
bool b = DEBUG || true;
}''');
}
test_statementAfterAlwaysThrowsFunction() async {
addMetaPackage();
await assertErrorsInCode(r'''
import 'package:meta/meta.dart';
@alwaysThrows
void a() {
throw 'msg';
}
f() {
var one = 1;
a();
var two = 2;
}''', [HintCode.DEAD_CODE]);
}
@failingTest
test_statementAfterAlwaysThrowsGetter() async {
addMetaPackage();
await assertErrorsInCode(r'''
import 'package:meta/meta.dart';
class C {
@alwaysThrows
int get a {
throw 'msg';
}
f() {
var one = 1;
new C().a;
var two = 2;
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterAlwaysThrowsMethod() async {
addMetaPackage();
await assertErrorsInCode(r'''
import 'package:meta/meta.dart';
class C {
@alwaysThrows
void a() {
throw 'msg';
}
}
f() {
var one = 1;
new C().a();
var two = 2;
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterBreak_inDefaultCase() async {
await assertErrorsInCode(r'''
f(v) {
switch(v) {
case 1:
default:
break;
var a;
}
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterBreak_inForEachStatement() async {
await assertErrorsInCode(r'''
f() {
var list;
for(var l in list) {
break;
var a;
}
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterBreak_inForStatement() async {
await assertErrorsInCode(r'''
f() {
for(;;) {
break;
var a;
}
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterBreak_inSwitchCase() async {
await assertErrorsInCode(r'''
f(v) {
switch(v) {
case 1:
break;
var a;
}
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterBreak_inWhileStatement() async {
await assertErrorsInCode(r'''
f(v) {
while(v) {
break;
var a;
}
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterContinue_inForEachStatement() async {
await assertErrorsInCode(r'''
f() {
var list;
for(var l in list) {
continue;
var a;
}
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterContinue_inForStatement() async {
await assertErrorsInCode(r'''
f() {
for(;;) {
continue;
var a;
}
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterContinue_inWhileStatement() async {
await assertErrorsInCode(r'''
f(v) {
while(v) {
continue;
var a;
}
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterExitingIf_returns() async {
await assertErrorsInCode(r'''
f() {
if (1 > 2) {
return;
} else {
return;
}
var one = 1;
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterIfWithoutElse() async {
await assertNoErrorsInCode(r'''
f() {
if (1 < 0) {
return;
}
int a = 1;
}''');
}
test_statementAfterRethrow() async {
await assertErrorsInCode(r'''
f() {
try {
var one = 1;
} catch (e) {
rethrow;
var two = 2;
}
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterReturn_function() async {
await assertErrorsInCode(r'''
f() {
var one = 1;
return;
var two = 2;
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterReturn_ifStatement() async {
await assertErrorsInCode(r'''
f(bool b) {
if(b) {
var one = 1;
return;
var two = 2;
}
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterReturn_method() async {
await assertErrorsInCode(r'''
class A {
m() {
var one = 1;
return;
var two = 2;
}
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterReturn_nested() async {
await assertErrorsInCode(r'''
f() {
var one = 1;
return;
if(false) {}
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterReturn_twoReturns() async {
await assertErrorsInCode(r'''
f() {
var one = 1;
return;
var two = 2;
return;
var three = 3;
}''', [HintCode.DEAD_CODE]);
}
test_statementAfterThrow() async {
await assertErrorsInCode(r'''
f() {
var one = 1;
throw 'Stop here';
var two = 2;
}''', [HintCode.DEAD_CODE]);
}
test_afterForEachWithBreakLabel() async {
await assertNoErrorsInCode(r'''
f() {
named: {
for (var x in [1]) {
if (x == null)
break named;
}
return;
}
print('not dead');
}
''');
}
test_afterForWithBreakLabel() async {
await assertNoErrorsInCode(r'''
f() {
named: {
for (int i = 0; i < 7; i++) {
if (i == null)
break named;
}
return;
}
print('not dead');
}
''');
}
}
@reflectiveTest
class UncheckedUseOfNullableValueTest extends DriverResolutionTest {
@override
AnalysisOptionsImpl get analysisOptions =>
AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
test_nullCoalesce_nonNullable() async {
await assertErrorsInCode(r'''
@pragma('analyzer:non-nullable')
library foo;
m() {
int x;
x ?? 1;
}
''', [HintCode.DEAD_CODE]);
}
test_nullCoalesce_nullable() async {
await assertNoErrorsInCode(r'''
@pragma('analyzer:non-nullable')
library foo;
m() {
int? x;
x ?? 1;
}
''');
}
test_nullCoalesceAssign_nonNullable() async {
await assertErrorsInCode(r'''
@pragma('analyzer:non-nullable')
library foo;
m() {
int x;
x ??= 1;
}
''', [HintCode.DEAD_CODE]);
}
test_nullCoalesceAssign_nullable() async {
await assertNoErrorsInCode(r'''
@pragma('analyzer:non-nullable')
library foo;
m() {
int? x;
x ??= 1;
}
''');
}
}