blob: fcb6c5ce699ea6173f4c60be731870b849ec8e30 [file] [log] [blame]
// Copyright (c) 2014, 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.
library engine.resolver_test;
import 'dart:collection';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/element_resolver.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/java_engine_io.dart';
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/sdk_io.dart' show DirectoryBasedDartSdk;
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/generated/static_type_analyzer.dart';
import 'package:analyzer/src/generated/testing/ast_factory.dart';
import 'package:analyzer/src/generated/testing/element_factory.dart';
import 'package:analyzer/src/generated/testing/test_type_provider.dart';
import 'package:analyzer/src/generated/testing/token_factory.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:unittest/unittest.dart';
import '../reflective_tests.dart';
import 'test_support.dart';
main() {
groupSep = ' | ';
runReflectiveTests(AnalysisDeltaTest);
runReflectiveTests(ChangeSetTest);
runReflectiveTests(EnclosedScopeTest);
runReflectiveTests(LibraryImportScopeTest);
runReflectiveTests(LibraryScopeTest);
runReflectiveTests(ScopeTest);
runReflectiveTests(ElementResolverTest);
runReflectiveTests(InheritanceManagerTest);
runReflectiveTests(LibraryElementBuilderTest);
runReflectiveTests(LibraryResolver2Test);
runReflectiveTests(LibraryResolverTest);
runReflectiveTests(LibraryTest);
runReflectiveTests(StaticTypeAnalyzerTest);
runReflectiveTests(StaticTypeAnalyzer2Test);
runReflectiveTests(SubtypeManagerTest);
runReflectiveTests(TypeOverrideManagerTest);
runReflectiveTests(TypeProviderImplTest);
runReflectiveTests(TypeResolverVisitorTest);
runReflectiveTests(CheckedModeCompileTimeErrorCodeTest);
runReflectiveTests(ErrorResolverTest);
runReflectiveTests(HintCodeTest);
runReflectiveTests(MemberMapTest);
runReflectiveTests(NonHintCodeTest);
runReflectiveTests(SimpleResolverTest);
runReflectiveTests(StrictModeTest);
runReflectiveTests(TypePropagationTest);
}
/**
* The class `AnalysisContextFactory` defines utility methods used to create analysis contexts
* for testing purposes.
*/
class AnalysisContextFactory {
static String _DART_MATH = "dart:math";
static String _DART_INTERCEPTORS = "dart:_interceptors";
static String _DART_JS_HELPER = "dart:_js_helper";
/**
* Create an analysis context that has a fake core library already resolved.
*
* @return the analysis context that was created
*/
static AnalysisContextImpl contextWithCore() {
AnalysisContextForTests context = new AnalysisContextForTests();
return initContextWithCore(context);
}
/**
* Create an analysis context that uses the given options and has a fake core library already
* resolved.
*
* @param options the options to be applied to the context
* @return the analysis context that was created
*/
static AnalysisContextImpl contextWithCoreAndOptions(
AnalysisOptions options) {
AnalysisContextForTests context = new AnalysisContextForTests();
context._internalSetAnalysisOptions(options);
return initContextWithCore(context);
}
/**
* Initialize the given analysis context with a fake core library already resolved.
*
* @param context the context to be initialized (not `null`)
* @return the analysis context that was created
*/
static AnalysisContextImpl initContextWithCore(AnalysisContextImpl context) {
DirectoryBasedDartSdk sdk = new _AnalysisContextFactory_initContextWithCore(
new JavaFile("/fake/sdk"));
SourceFactory sourceFactory =
new SourceFactory([new DartUriResolver(sdk), new FileUriResolver()]);
context.sourceFactory = sourceFactory;
AnalysisContext coreContext = sdk.context;
//
// dart:core
//
TestTypeProvider provider = new TestTypeProvider();
CompilationUnitElementImpl coreUnit =
new CompilationUnitElementImpl("core.dart");
Source coreSource = sourceFactory.forUri(DartSdk.DART_CORE);
coreContext.setContents(coreSource, "");
coreUnit.source = coreSource;
ClassElementImpl proxyClassElement = ElementFactory.classElement2("_Proxy");
coreUnit.types = <ClassElement>[
provider.boolType.element,
provider.deprecatedType.element,
provider.doubleType.element,
provider.functionType.element,
provider.intType.element,
provider.iterableType.element,
provider.iteratorType.element,
provider.listType.element,
provider.mapType.element,
provider.nullType.element,
provider.numType.element,
provider.objectType.element,
proxyClassElement,
provider.stackTraceType.element,
provider.stringType.element,
provider.symbolType.element,
provider.typeType.element
];
coreUnit.functions = <FunctionElement>[
ElementFactory.functionElement3("identical", provider.boolType.element,
<ClassElement>[
provider.objectType.element,
provider.objectType.element
], null),
ElementFactory.functionElement3("print", VoidTypeImpl.instance.element,
<ClassElement>[provider.objectType.element], null)
];
TopLevelVariableElement proxyTopLevelVariableElt = ElementFactory
.topLevelVariableElement3("proxy", true, false, proxyClassElement.type);
TopLevelVariableElement deprecatedTopLevelVariableElt = ElementFactory
.topLevelVariableElement3(
"deprecated", true, false, provider.deprecatedType);
coreUnit.accessors = <PropertyAccessorElement>[
proxyTopLevelVariableElt.getter,
deprecatedTopLevelVariableElt.getter
];
coreUnit.topLevelVariables = <TopLevelVariableElement>[
proxyTopLevelVariableElt,
deprecatedTopLevelVariableElt
];
LibraryElementImpl coreLibrary = new LibraryElementImpl.forNode(
coreContext, AstFactory.libraryIdentifier2(["dart", "core"]));
coreLibrary.definingCompilationUnit = coreUnit;
//
// dart:async
//
CompilationUnitElementImpl asyncUnit =
new CompilationUnitElementImpl("async.dart");
Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
coreContext.setContents(asyncSource, "");
asyncUnit.source = asyncSource;
// Future
ClassElementImpl futureElement =
ElementFactory.classElement2("Future", ["T"]);
InterfaceType futureType = futureElement.type;
// factory Future.value([value])
ConstructorElementImpl futureConstructor =
ElementFactory.constructorElement2(futureElement, "value");
futureConstructor.parameters = <ParameterElement>[
ElementFactory.positionalParameter2("value", provider.dynamicType)
];
futureConstructor.factory = true;
(futureConstructor.type as FunctionTypeImpl).typeArguments =
futureElement.type.typeArguments;
futureElement.constructors = <ConstructorElement>[futureConstructor];
// Future then(onValue(T value), { Function onError });
List<ParameterElement> parameters = <ParameterElement>[
ElementFactory.requiredParameter2(
"value", futureElement.typeParameters[0].type)
];
FunctionTypeAliasElementImpl aliasElement =
new FunctionTypeAliasElementImpl.forNode(null);
aliasElement.synthetic = true;
aliasElement.parameters = parameters;
aliasElement.returnType = provider.dynamicType;
aliasElement.enclosingElement = asyncUnit;
FunctionTypeImpl aliasType = new FunctionTypeImpl.con2(aliasElement);
aliasElement.shareTypeParameters(futureElement.typeParameters);
aliasType.typeArguments = futureElement.type.typeArguments;
MethodElement thenMethod = ElementFactory.methodElementWithParameters(
"then", futureElement.type.typeArguments, futureType, [
ElementFactory.requiredParameter2("onValue", aliasType),
ElementFactory.namedParameter2("onError", provider.functionType)
]);
futureElement.methods = <MethodElement>[thenMethod];
// Completer
ClassElementImpl completerElement =
ElementFactory.classElement2("Completer", ["T"]);
ConstructorElementImpl completerConstructor =
ElementFactory.constructorElement2(completerElement, null);
(completerConstructor.type as FunctionTypeImpl).typeArguments =
completerElement.type.typeArguments;
completerElement.constructors = <ConstructorElement>[completerConstructor];
asyncUnit.types = <ClassElement>[
completerElement,
futureElement,
ElementFactory.classElement2("Stream", ["T"])
];
LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
coreContext, AstFactory.libraryIdentifier2(["dart", "async"]));
asyncLibrary.definingCompilationUnit = asyncUnit;
//
// dart:html
//
CompilationUnitElementImpl htmlUnit =
new CompilationUnitElementImpl("html_dartium.dart");
Source htmlSource = sourceFactory.forUri(DartSdk.DART_HTML);
coreContext.setContents(htmlSource, "");
htmlUnit.source = htmlSource;
ClassElementImpl elementElement = ElementFactory.classElement2("Element");
InterfaceType elementType = elementElement.type;
ClassElementImpl canvasElement =
ElementFactory.classElement("CanvasElement", elementType);
ClassElementImpl contextElement =
ElementFactory.classElement2("CanvasRenderingContext");
InterfaceType contextElementType = contextElement.type;
ClassElementImpl context2dElement = ElementFactory.classElement(
"CanvasRenderingContext2D", contextElementType);
canvasElement.methods = <MethodElement>[
ElementFactory.methodElement(
"getContext", contextElementType, [provider.stringType])
];
canvasElement.accessors = <PropertyAccessorElement>[
ElementFactory.getterElement("context2D", false, context2dElement.type)
];
canvasElement.fields = canvasElement.accessors
.map((PropertyAccessorElement accessor) => accessor.variable)
.toList();
ClassElementImpl documentElement =
ElementFactory.classElement("Document", elementType);
ClassElementImpl htmlDocumentElement =
ElementFactory.classElement("HtmlDocument", documentElement.type);
htmlDocumentElement.methods = <MethodElement>[
ElementFactory.methodElement(
"query", elementType, <DartType>[provider.stringType])
];
htmlUnit.types = <ClassElement>[
ElementFactory.classElement("AnchorElement", elementType),
ElementFactory.classElement("BodyElement", elementType),
ElementFactory.classElement("ButtonElement", elementType),
canvasElement,
contextElement,
context2dElement,
ElementFactory.classElement("DivElement", elementType),
documentElement,
elementElement,
htmlDocumentElement,
ElementFactory.classElement("InputElement", elementType),
ElementFactory.classElement("SelectElement", elementType)
];
htmlUnit.functions = <FunctionElement>[
ElementFactory.functionElement3("query", elementElement,
<ClassElement>[provider.stringType.element],
ClassElementImpl.EMPTY_ARRAY)
];
TopLevelVariableElementImpl document = ElementFactory
.topLevelVariableElement3(
"document", false, true, htmlDocumentElement.type);
htmlUnit.topLevelVariables = <TopLevelVariableElement>[document];
htmlUnit.accessors = <PropertyAccessorElement>[document.getter];
LibraryElementImpl htmlLibrary = new LibraryElementImpl.forNode(
coreContext, AstFactory.libraryIdentifier2(["dart", "dom", "html"]));
htmlLibrary.definingCompilationUnit = htmlUnit;
//
// dart:math
//
CompilationUnitElementImpl mathUnit =
new CompilationUnitElementImpl("math.dart");
Source mathSource = sourceFactory.forUri(_DART_MATH);
coreContext.setContents(mathSource, "");
mathUnit.source = mathSource;
FunctionElement cosElement = ElementFactory.functionElement3("cos",
provider.doubleType.element, <ClassElement>[provider.numType.element],
ClassElementImpl.EMPTY_ARRAY);
TopLevelVariableElement ln10Element = ElementFactory
.topLevelVariableElement3("LN10", true, false, provider.doubleType);
TopLevelVariableElement piElement = ElementFactory.topLevelVariableElement3(
"PI", true, false, provider.doubleType);
ClassElementImpl randomElement = ElementFactory.classElement2("Random");
randomElement.abstract = true;
ConstructorElementImpl randomConstructor =
ElementFactory.constructorElement2(randomElement, null);
randomConstructor.factory = true;
ParameterElementImpl seedParam = new ParameterElementImpl("seed", 0);
seedParam.parameterKind = ParameterKind.POSITIONAL;
seedParam.type = provider.intType;
randomConstructor.parameters = <ParameterElement>[seedParam];
randomElement.constructors = <ConstructorElement>[randomConstructor];
FunctionElement sinElement = ElementFactory.functionElement3("sin",
provider.doubleType.element, <ClassElement>[provider.numType.element],
ClassElementImpl.EMPTY_ARRAY);
FunctionElement sqrtElement = ElementFactory.functionElement3("sqrt",
provider.doubleType.element, <ClassElement>[provider.numType.element],
ClassElementImpl.EMPTY_ARRAY);
mathUnit.accessors = <PropertyAccessorElement>[
ln10Element.getter,
piElement.getter
];
mathUnit.functions = <FunctionElement>[cosElement, sinElement, sqrtElement];
mathUnit.topLevelVariables = <TopLevelVariableElement>[
ln10Element,
piElement
];
mathUnit.types = <ClassElement>[randomElement];
LibraryElementImpl mathLibrary = new LibraryElementImpl.forNode(
coreContext, AstFactory.libraryIdentifier2(["dart", "math"]));
mathLibrary.definingCompilationUnit = mathUnit;
//
// Set empty sources for the rest of the libraries.
//
Source source = sourceFactory.forUri(_DART_INTERCEPTORS);
coreContext.setContents(source, "");
source = sourceFactory.forUri(_DART_JS_HELPER);
coreContext.setContents(source, "");
//
// Record the elements.
//
HashMap<Source, LibraryElement> elementMap =
new HashMap<Source, LibraryElement>();
elementMap[coreSource] = coreLibrary;
elementMap[asyncSource] = asyncLibrary;
elementMap[htmlSource] = htmlLibrary;
elementMap[mathSource] = mathLibrary;
context.recordLibraryElements(elementMap);
return context;
}
}
/**
* Instances of the class `AnalysisContextForTests` implement an analysis context that has a
* fake SDK that is much smaller and faster for testing purposes.
*/
class AnalysisContextForTests extends AnalysisContextImpl {
@override
void set analysisOptions(AnalysisOptions options) {
AnalysisOptions currentOptions = analysisOptions;
bool needsRecompute = currentOptions.analyzeFunctionBodiesPredicate !=
options.analyzeFunctionBodiesPredicate ||
currentOptions.generateImplicitErrors !=
options.generateImplicitErrors ||
currentOptions.generateSdkErrors != options.generateSdkErrors ||
currentOptions.dart2jsHint != options.dart2jsHint ||
(currentOptions.hint && !options.hint) ||
currentOptions.preserveComments != options.preserveComments ||
currentOptions.enableNullAwareOperators !=
options.enableNullAwareOperators ||
currentOptions.enableStrictCallChecks != options.enableStrictCallChecks;
if (needsRecompute) {
fail(
"Cannot set options that cause the sources to be reanalyzed in a test context");
}
super.analysisOptions = options;
}
@override
bool exists(Source source) =>
super.exists(source) || sourceFactory.dartSdk.context.exists(source);
@override
TimestampedData<String> getContents(Source source) {
if (source.isInSystemLibrary) {
return sourceFactory.dartSdk.context.getContents(source);
}
return super.getContents(source);
}
@override
int getModificationStamp(Source source) {
if (source.isInSystemLibrary) {
return sourceFactory.dartSdk.context.getModificationStamp(source);
}
return super.getModificationStamp(source);
}
/**
* Set the analysis options, even if they would force re-analysis. This method should only be
* invoked before the fake SDK is initialized.
*
* @param options the analysis options to be set
*/
void _internalSetAnalysisOptions(AnalysisOptions options) {
super.analysisOptions = options;
}
}
/**
* Helper for creating and managing single [AnalysisContext].
*/
class AnalysisContextHelper {
AnalysisContext context;
/**
* Creates new [AnalysisContext] using [AnalysisContextFactory.contextWithCore].
*/
AnalysisContextHelper() {
context = AnalysisContextFactory.contextWithCore();
AnalysisOptionsImpl options =
new AnalysisOptionsImpl.con1(context.analysisOptions);
options.cacheSize = 256;
context.analysisOptions = options;
}
Source addSource(String path, String code) {
Source source = new FileBasedSource.con1(FileUtilities2.createFile(path));
if (path.endsWith(".dart") || path.endsWith(".html")) {
ChangeSet changeSet = new ChangeSet();
changeSet.addedSource(source);
context.applyChanges(changeSet);
}
context.setContents(source, code);
return source;
}
CompilationUnitElement getDefiningUnitElement(Source source) =>
context.getCompilationUnitElement(source, source);
CompilationUnit resolveDefiningUnit(Source source) {
LibraryElement libraryElement = context.computeLibraryElement(source);
return context.resolveCompilationUnit(source, libraryElement);
}
void runTasks() {
AnalysisResult result = context.performAnalysisTask();
while (result.changeNotices != null) {
result = context.performAnalysisTask();
}
}
}
@reflectiveTest
class AnalysisDeltaTest extends EngineTestCase {
TestSource source1 = new TestSource('/1.dart');
TestSource source2 = new TestSource('/2.dart');
TestSource source3 = new TestSource('/3.dart');
void test_getAddedSources() {
AnalysisDelta delta = new AnalysisDelta();
delta.setAnalysisLevel(source1, AnalysisLevel.ALL);
delta.setAnalysisLevel(source2, AnalysisLevel.ERRORS);
delta.setAnalysisLevel(source3, AnalysisLevel.NONE);
List<Source> addedSources = delta.addedSources;
expect(addedSources, hasLength(2));
expect(addedSources, unorderedEquals([source1, source2]));
}
void test_getAnalysisLevels() {
AnalysisDelta delta = new AnalysisDelta();
expect(delta.analysisLevels.length, 0);
}
void test_setAnalysisLevel() {
AnalysisDelta delta = new AnalysisDelta();
delta.setAnalysisLevel(source1, AnalysisLevel.ALL);
delta.setAnalysisLevel(source2, AnalysisLevel.ERRORS);
Map<Source, AnalysisLevel> levels = delta.analysisLevels;
expect(levels.length, 2);
expect(levels[source1], AnalysisLevel.ALL);
expect(levels[source2], AnalysisLevel.ERRORS);
}
void test_toString() {
AnalysisDelta delta = new AnalysisDelta();
delta.setAnalysisLevel(new TestSource(), AnalysisLevel.ALL);
String result = delta.toString();
expect(result, isNotNull);
expect(result.length > 0, isTrue);
}
}
@reflectiveTest
class ChangeSetTest extends EngineTestCase {
void test_changedContent() {
TestSource source = new TestSource();
String content = "";
ChangeSet changeSet = new ChangeSet();
changeSet.changedContent(source, content);
expect(changeSet.addedSources, hasLength(0));
expect(changeSet.changedSources, hasLength(0));
Map<Source, String> map = changeSet.changedContents;
expect(map, hasLength(1));
expect(map[source], same(content));
expect(changeSet.changedRanges, hasLength(0));
expect(changeSet.deletedSources, hasLength(0));
expect(changeSet.removedSources, hasLength(0));
expect(changeSet.removedContainers, hasLength(0));
}
void test_changedRange() {
TestSource source = new TestSource();
String content = "";
ChangeSet changeSet = new ChangeSet();
changeSet.changedRange(source, content, 1, 2, 3);
expect(changeSet.addedSources, hasLength(0));
expect(changeSet.changedSources, hasLength(0));
expect(changeSet.changedContents, hasLength(0));
Map<Source, ChangeSet_ContentChange> map = changeSet.changedRanges;
expect(map, hasLength(1));
ChangeSet_ContentChange change = map[source];
expect(change, isNotNull);
expect(change.contents, content);
expect(change.offset, 1);
expect(change.oldLength, 2);
expect(change.newLength, 3);
expect(changeSet.deletedSources, hasLength(0));
expect(changeSet.removedSources, hasLength(0));
expect(changeSet.removedContainers, hasLength(0));
}
void test_toString() {
ChangeSet changeSet = new ChangeSet();
changeSet.addedSource(new TestSource());
changeSet.changedSource(new TestSource());
changeSet.changedContent(new TestSource(), "");
changeSet.changedRange(new TestSource(), "", 0, 0, 0);
changeSet.deletedSource(new TestSource());
changeSet.removedSource(new TestSource());
changeSet
.removedContainer(new SourceContainer_ChangeSetTest_test_toString());
expect(changeSet.toString(), isNotNull);
}
}
@reflectiveTest
class CheckedModeCompileTimeErrorCodeTest extends ResolverTestCase {
void test_fieldFormalParameterAssignableToField_extends() {
// According to checked-mode type checking rules, a value of type B is
// assignable to a field of type A, because B extends A (and hence is a
// subtype of A).
Source source = addSource(r'''
class A {
const A();
}
class B extends A {
const B();
}
class C {
final A a;
const C(this.a);
}
var v = const C(const B());''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_fieldFormalParameterAssignableToField_fieldType_unresolved_null() {
// Null always passes runtime type checks, even when the type is
// unresolved.
Source source = addSource(r'''
class A {
final Unresolved x;
const A(String this.x);
}
var v = const A(null);''');
resolve(source);
assertErrors(source, [StaticWarningCode.UNDEFINED_CLASS]);
verify([source]);
}
void test_fieldFormalParameterAssignableToField_implements() {
// According to checked-mode type checking rules, a value of type B is
// assignable to a field of type A, because B implements A (and hence is a
// subtype of A).
Source source = addSource(r'''
class A {}
class B implements A {
const B();
}
class C {
final A a;
const C(this.a);
}
var v = const C(const B());''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_fieldFormalParameterAssignableToField_list_dynamic() {
// [1, 2, 3] has type List<dynamic>, which is a subtype of List<int>.
Source source = addSource(r'''
class A {
const A(List<int> x);
}
var x = const A(const [1, 2, 3]);''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_fieldFormalParameterAssignableToField_list_nonDynamic() {
// <int>[1, 2, 3] has type List<int>, which is a subtype of List<num>.
Source source = addSource(r'''
class A {
const A(List<num> x);
}
var x = const A(const <int>[1, 2, 3]);''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_fieldFormalParameterAssignableToField_map_dynamic() {
// {1: 2} has type Map<dynamic, dynamic>, which is a subtype of
// Map<int, int>.
Source source = addSource(r'''
class A {
const A(Map<int, int> x);
}
var x = const A(const {1: 2});''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_fieldFormalParameterAssignableToField_map_keyDifferent() {
// <int, int>{1: 2} has type Map<int, int>, which is a subtype of
// Map<num, int>.
Source source = addSource(r'''
class A {
const A(Map<num, int> x);
}
var x = const A(const <int, int>{1: 2});''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_fieldFormalParameterAssignableToField_map_valueDifferent() {
// <int, int>{1: 2} has type Map<int, int>, which is a subtype of
// Map<int, num>.
Source source = addSource(r'''
class A {
const A(Map<int, num> x);
}
var x = const A(const <int, int>{1: 2});''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_fieldFormalParameterAssignableToField_notype() {
// If a field is declared without a type, then any value may be assigned to
// it.
Source source = addSource(r'''
class A {
final x;
const A(this.x);
}
var v = const A(5);''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_fieldFormalParameterAssignableToField_null() {
// Null is assignable to anything.
Source source = addSource(r'''
class A {
final int x;
const A(this.x);
}
var v = const A(null);''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_fieldFormalParameterAssignableToField_typedef() {
// foo has the runtime type dynamic -> dynamic, so it should be assignable
// to A.f.
Source source = addSource(r'''
typedef String Int2String(int x);
class A {
final Int2String f;
const A(this.f);
}
foo(x) => 1;
var v = const A(foo);''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_fieldFormalParameterAssignableToField_typeSubstitution() {
// foo has the runtime type dynamic -> dynamic, so it should be assignable
// to A.f.
Source source = addSource(r'''
class A<T> {
final T x;
const A(this.x);
}
var v = const A<int>(3);''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_fieldFormalParameterNotAssignableToField() {
Source source = addSource(r'''
class A {
final int x;
const A(this.x);
}
var v = const A('foo');''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE
]);
verify([source]);
}
void test_fieldFormalParameterNotAssignableToField_extends() {
// According to checked-mode type checking rules, a value of type A is not
// assignable to a field of type B, because B extends A (the subtyping
// relationship is in the wrong direction).
Source source = addSource(r'''
class A {
const A();
}
class B extends A {
const B();
}
class C {
final B b;
const C(this.b);
}
var v = const C(const A());''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH
]);
verify([source]);
}
void test_fieldFormalParameterNotAssignableToField_fieldType() {
Source source = addSource(r'''
class A {
final int x;
const A(String this.x);
}
var v = const A('foo');''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
StaticWarningCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE
]);
verify([source]);
}
void test_fieldFormalParameterNotAssignableToField_fieldType_unresolved() {
Source source = addSource(r'''
class A {
final Unresolved x;
const A(String this.x);
}
var v = const A('foo');''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
StaticWarningCode.UNDEFINED_CLASS
]);
verify([source]);
}
void test_fieldFormalParameterNotAssignableToField_implements() {
// According to checked-mode type checking rules, a value of type A is not
// assignable to a field of type B, because B implements A (the subtyping
// relationship is in the wrong direction).
Source source = addSource(r'''
class A {
const A();
}
class B implements A {}
class C {
final B b;
const C(this.b);
}
var v = const C(const A());''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH
]);
verify([source]);
}
void test_fieldFormalParameterNotAssignableToField_list() {
// <num>[1, 2, 3] has type List<num>, which is not a subtype of List<int>.
Source source = addSource(r'''
class A {
const A(List<int> x);
}
var x = const A(const <num>[1, 2, 3]);''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH
]);
verify([source]);
}
void test_fieldFormalParameterNotAssignableToField_map_keyMismatch() {
// <num, int>{1: 2} has type Map<num, int>, which is not a subtype of
// Map<int, int>.
Source source = addSource(r'''
class A {
const A(Map<int, int> x);
}
var x = const A(const <num, int>{1: 2});''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH
]);
verify([source]);
}
void test_fieldFormalParameterNotAssignableToField_map_valueMismatch() {
// <int, num>{1: 2} has type Map<int, num>, which is not a subtype of
// Map<int, int>.
Source source = addSource(r'''
class A {
const A(Map<int, int> x);
}
var x = const A(const <int, num>{1: 2});''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH
]);
verify([source]);
}
void test_fieldFormalParameterNotAssignableToField_optional() {
Source source = addSource(r'''
class A {
final int x;
const A([this.x = 'foo']);
}
var v = const A();''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
StaticTypeWarningCode.INVALID_ASSIGNMENT
]);
verify([source]);
}
void test_fieldFormalParameterNotAssignableToField_typedef() {
// foo has the runtime type String -> int, so it should not be assignable
// to A.f (A.f requires it to be int -> String).
Source source = addSource(r'''
typedef String Int2String(int x);
class A {
final Int2String f;
const A(this.f);
}
int foo(String x) => 1;
var v = const A(foo);''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE
]);
verify([source]);
}
void test_fieldInitializerNotAssignable() {
Source source = addSource(r'''
class A {
final int x;
const A() : x = '';
}''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE,
StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE
]);
verify([source]);
}
void test_fieldTypeMismatch() {
Source source = addSource(r'''
class A {
const A(x) : y = x;
final int y;
}
var v = const A('foo');''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH
]);
verify([source]);
}
void test_fieldTypeMismatch_unresolved() {
Source source = addSource(r'''
class A {
const A(x) : y = x;
final Unresolved y;
}
var v = const A('foo');''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
StaticWarningCode.UNDEFINED_CLASS
]);
verify([source]);
}
void test_fieldTypeOk_null() {
Source source = addSource(r'''
class A {
const A(x) : y = x;
final int y;
}
var v = const A(null);''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_fieldTypeOk_unresolved_null() {
// Null always passes runtime type checks, even when the type is
// unresolved.
Source source = addSource(r'''
class A {
const A(x) : y = x;
final Unresolved y;
}
var v = const A(null);''');
resolve(source);
assertErrors(source, [StaticWarningCode.UNDEFINED_CLASS]);
verify([source]);
}
void test_listElementTypeNotAssignable() {
Source source = addSource("var v = const <String> [42];");
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE,
StaticWarningCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE
]);
verify([source]);
}
void test_mapKeyTypeNotAssignable() {
Source source = addSource("var v = const <String, int > {1 : 2};");
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.MAP_KEY_TYPE_NOT_ASSIGNABLE,
StaticWarningCode.MAP_KEY_TYPE_NOT_ASSIGNABLE
]);
verify([source]);
}
void test_mapValueTypeNotAssignable() {
Source source = addSource("var v = const <String, String> {'a' : 2};");
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE,
StaticWarningCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE
]);
verify([source]);
}
void test_parameterAssignable_null() {
// Null is assignable to anything.
Source source = addSource(r'''
class A {
const A(int x);
}
var v = const A(null);''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_parameterAssignable_typeSubstitution() {
Source source = addSource(r'''
class A<T> {
const A(T x);
}
var v = const A<int>(3);''');
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_parameterAssignable_undefined_null() {
// Null always passes runtime type checks, even when the type is
// unresolved.
Source source = addSource(r'''
class A {
const A(Unresolved x);
}
var v = const A(null);''');
resolve(source);
assertErrors(source, [StaticWarningCode.UNDEFINED_CLASS]);
verify([source]);
}
void test_parameterNotAssignable() {
Source source = addSource(r'''
class A {
const A(int x);
}
var v = const A('foo');''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE
]);
verify([source]);
}
void test_parameterNotAssignable_typeSubstitution() {
Source source = addSource(r'''
class A<T> {
const A(T x);
}
var v = const A<int>('foo');''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE
]);
verify([source]);
}
void test_parameterNotAssignable_undefined() {
Source source = addSource(r'''
class A {
const A(Unresolved x);
}
var v = const A('foo');''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH,
StaticWarningCode.UNDEFINED_CLASS
]);
verify([source]);
}
void test_redirectingConstructor_paramTypeMismatch() {
Source source = addSource(r'''
class A {
const A.a1(x) : this.a2(x);
const A.a2(String x);
}
var v = const A.a1(0);''');
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH
]);
verify([source]);
}
void test_topLevelVarAssignable_null() {
Source source = addSource("const int x = null;");
resolve(source);
assertNoErrors(source);
verify([source]);
}
void test_topLevelVarAssignable_undefined_null() {
// Null always passes runtime type checks, even when the type is
// unresolved.
Source source = addSource("const Unresolved x = null;");
resolve(source);
assertErrors(source, [StaticWarningCode.UNDEFINED_CLASS]);
verify([source]);
}
void test_topLevelVarNotAssignable() {
Source source = addSource("const int x = 'foo';");
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH,
StaticTypeWarningCode.INVALID_ASSIGNMENT
]);
verify([source]);
}
void test_topLevelVarNotAssignable_undefined() {
Source source = addSource("const Unresolved x = 'foo';");
resolve(source);
assertErrors(source, [
CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH,
StaticWarningCode.UNDEFINED_CLASS
]);
verify([source]);
}
}
@reflectiveTest
class ElementResolverTest extends EngineTestCase {
/**
* The error listener to which errors will be reported.
*/
GatheringErrorListener _listener;
/**
* The type provider used to access the types.
*/
TestTypeProvider _typeProvider;
/**
* The library containing the code being resolved.
*/
LibraryElementImpl _definingLibrary;
/**
* The resolver visitor that maintains the state for the resolver.
*/
ResolverVisitor _visitor;
/**
* The resolver being used to resolve the test cases.
*/
ElementResolver _resolver;
void fail_visitExportDirective_combinators() {
fail("Not yet tested");
// Need to set up the exported library so that the identifier can be
// resolved.
ExportDirective directive =
AstFactory.exportDirective2(null, [AstFactory.hideCombinator2(["A"])]);
_resolveNode(directive);
_listener.assertNoErrors();
}
void fail_visitFunctionExpressionInvocation() {
fail("Not yet tested");
_listener.assertNoErrors();
}
void fail_visitImportDirective_combinators_noPrefix() {
fail("Not yet tested");
// Need to set up the imported library so that the identifier can be
// resolved.
ImportDirective directive = AstFactory.importDirective3(
null, null, [AstFactory.showCombinator2(["A"])]);
_resolveNode(directive);
_listener.assertNoErrors();
}
void fail_visitImportDirective_combinators_prefix() {
fail("Not yet tested");
// Need to set up the imported library so that the identifiers can be
// resolved.
String prefixName = "p";
_definingLibrary.imports = <ImportElement>[
ElementFactory.importFor(null, ElementFactory.prefix(prefixName))
];
ImportDirective directive = AstFactory.importDirective3(null, prefixName, [
AstFactory.showCombinator2(["A"]),
AstFactory.hideCombinator2(["B"])
]);
_resolveNode(directive);
_listener.assertNoErrors();
}
void fail_visitRedirectingConstructorInvocation() {
fail("Not yet tested");
_listener.assertNoErrors();
}
@override
void setUp() {
_listener = new GatheringErrorListener();
_typeProvider = new TestTypeProvider();
_resolver = _createResolver();
}
void test_lookUpMethodInInterfaces() {
InterfaceType intType = _typeProvider.intType;
//
// abstract class A { int operator[](int index); }
//
ClassElementImpl classA = ElementFactory.classElement2("A");
MethodElement operator =
ElementFactory.methodElement("[]", intType, [intType]);
classA.methods = <MethodElement>[operator];
//
// class B implements A {}
//
ClassElementImpl classB = ElementFactory.classElement2("B");
classB.interfaces = <InterfaceType>[classA.type];
//
// class C extends Object with B {}
//
ClassElementImpl classC = ElementFactory.classElement2("C");
classC.mixins = <InterfaceType>[classB.type];
//
// class D extends C {}
//
ClassElementImpl classD = ElementFactory.classElement("D", classC.type);
//
// D a;
// a[i];
//
SimpleIdentifier array = AstFactory.identifier3("a");
array.staticType = classD.type;
IndexExpression expression =
AstFactory.indexExpression(array, AstFactory.identifier3("i"));
expect(_resolveIndexExpression(expression), same(operator));
_listener.assertNoErrors();
}
void test_visitAssignmentExpression_compound() {
InterfaceType intType = _typeProvider.intType;
SimpleIdentifier leftHandSide = AstFactory.identifier3("a");
leftHandSide.staticType = intType;
AssignmentExpression assignment = AstFactory.assignmentExpression(
leftHandSide, TokenType.PLUS_EQ, AstFactory.integer(1));
_resolveNode(assignment);
expect(
assignment.staticElement, same(getMethod(_typeProvider.numType, "+")));
_listener.assertNoErrors();
}
void test_visitAssignmentExpression_simple() {
AssignmentExpression expression = AstFactory.assignmentExpression(
AstFactory.identifier3("x"), TokenType.EQ, AstFactory.integer(0));
_resolveNode(expression);
expect(expression.staticElement, isNull);
_listener.assertNoErrors();
}
void test_visitBinaryExpression_bangEq() {
// String i;
// var j;
// i == j
InterfaceType stringType = _typeProvider.stringType;
SimpleIdentifier left = AstFactory.identifier3("i");
left.staticType = stringType;
BinaryExpression expression = AstFactory.binaryExpression(
left, TokenType.BANG_EQ, AstFactory.identifier3("j"));
_resolveNode(expression);
var stringElement = stringType.element;
expect(expression.staticElement, isNotNull);
expect(expression.staticElement, stringElement.lookUpMethod(
TokenType.EQ_EQ.lexeme, stringElement.library));
expect(expression.propagatedElement, isNull);
_listener.assertNoErrors();
}
void test_visitBinaryExpression_eq() {
// String i;
// var j;
// i == j
InterfaceType stringType = _typeProvider.stringType;
SimpleIdentifier left = AstFactory.identifier3("i");
left.staticType = stringType;
BinaryExpression expression = AstFactory.binaryExpression(
left, TokenType.EQ_EQ, AstFactory.identifier3("j"));
_resolveNode(expression);
var stringElement = stringType.element;
expect(expression.staticElement, stringElement.lookUpMethod(
TokenType.EQ_EQ.lexeme, stringElement.library));
expect(expression.propagatedElement, isNull);
_listener.assertNoErrors();
}
void test_visitBinaryExpression_plus() {
// num i;
// var j;
// i + j
InterfaceType numType = _typeProvider.numType;
SimpleIdentifier left = AstFactory.identifier3("i");
left.staticType = numType;
BinaryExpression expression = AstFactory.binaryExpression(
left, TokenType.PLUS, AstFactory.identifier3("j"));
_resolveNode(expression);
expect(expression.staticElement, getMethod(numType, "+"));
expect(expression.propagatedElement, isNull);
_listener.assertNoErrors();
}
void test_visitBinaryExpression_plus_propagatedElement() {
// var i = 1;
// var j;
// i + j
InterfaceType numType = _typeProvider.numType;
SimpleIdentifier left = AstFactory.identifier3("i");
left.propagatedType = numType;
BinaryExpression expression = AstFactory.binaryExpression(
left, TokenType.PLUS, AstFactory.identifier3("j"));
_resolveNode(expression);
expect(expression.staticElement, isNull);
expect(expression.propagatedElement, getMethod(numType, "+"));
_listener.assertNoErrors();
}
void test_visitBreakStatement_withLabel() {
// loop: while (true) {
// break loop;
// }
String label = "loop";
LabelElementImpl labelElement =
new LabelElementImpl(AstFactory.identifier3(label), false, false);
BreakStatement breakStatement = AstFactory.breakStatement2(label);
Expression condition = AstFactory.booleanLiteral(true);
WhileStatement whileStatement =
AstFactory.whileStatement(condition, breakStatement);
expect(_resolveBreak(breakStatement, labelElement, whileStatement),
same(labelElement));
expect(breakStatement.target, same(whileStatement));
_listener.assertNoErrors();
}
void test_visitBreakStatement_withoutLabel() {
BreakStatement statement = AstFactory.breakStatement();
_resolveStatement(statement, null, null);
_listener.assertNoErrors();
}
void test_visitConstructorName_named() {
ClassElementImpl classA = ElementFactory.classElement2("A");
String constructorName = "a";
ConstructorElement constructor =
ElementFactory.constructorElement2(classA, constructorName);
classA.constructors = <ConstructorElement>[constructor];
ConstructorName name = AstFactory.constructorName(
AstFactory.typeName(classA), constructorName);
_resolveNode(name);
expect(name.staticElement, same(constructor));
_listener.assertNoErrors();
}
void test_visitConstructorName_unnamed() {
ClassElementImpl classA = ElementFactory.classElement2("A");
String constructorName = null;
ConstructorElement constructor =
ElementFactory.constructorElement2(classA, constructorName);
classA.constructors = <ConstructorElement>[constructor];
ConstructorName name = AstFactory.constructorName(
AstFactory.typeName(classA), constructorName);
_resolveNode(name);
expect(name.staticElement, same(constructor));
_listener.assertNoErrors();
}
void test_visitContinueStatement_withLabel() {
// loop: while (true) {
// continue loop;
// }
String label = "loop";
LabelElementImpl labelElement =
new LabelElementImpl(AstFactory.identifier3(label), false, false);
ContinueStatement continueStatement = AstFactory.continueStatement(label);
Expression condition = AstFactory.booleanLiteral(true);
WhileStatement whileStatement =
AstFactory.whileStatement(condition, continueStatement);
expect(_resolveContinue(continueStatement, labelElement, whileStatement),
same(labelElement));
expect(continueStatement.target, same(whileStatement));
_listener.assertNoErrors();
}
void test_visitContinueStatement_withoutLabel() {
ContinueStatement statement = AstFactory.continueStatement();
_resolveStatement(statement, null, null);
_listener.assertNoErrors();
}
void test_visitExportDirective_noCombinators() {
ExportDirective directive = AstFactory.exportDirective2(null);
directive.element = ElementFactory
.exportFor(ElementFactory.library(_definingLibrary.context, "lib"));
_resolveNode(directive);
_listener.assertNoErrors();
}
void test_visitFieldFormalParameter() {
String fieldName = "f";
InterfaceType intType = _typeProvider.intType;
FieldElementImpl fieldElement =
ElementFactory.fieldElement(fieldName, false, false, false, intType);
ClassElementImpl classA = ElementFactory.classElement2("A");
classA.fields = <FieldElement>[fieldElement];
FieldFormalParameter parameter =
AstFactory.fieldFormalParameter2(fieldName);
FieldFormalParameterElementImpl parameterElement =
ElementFactory.fieldFormalParameter(parameter.identifier);
parameterElement.field = fieldElement;
parameterElement.type = intType;
parameter.identifier.staticElement = parameterElement;
_resolveInClass(parameter, classA);
expect(parameter.element.type, same(intType));
}
void test_visitImportDirective_noCombinators_noPrefix() {
ImportDirective directive = AstFactory.importDirective3(null, null);
directive.element = ElementFactory.importFor(
ElementFactory.library(_definingLibrary.context, "lib"), null);
_resolveNode(directive);
_listener.assertNoErrors();
}
void test_visitImportDirective_noCombinators_prefix() {
String prefixName = "p";
ImportElement importElement = ElementFactory.importFor(
ElementFactory.library(_definingLibrary.context, "lib"),
ElementFactory.prefix(prefixName));
_definingLibrary.imports = <ImportElement>[importElement];
ImportDirective directive = AstFactory.importDirective3(null, prefixName);
directive.element = importElement;
_resolveNode(directive);
_listener.assertNoErrors();
}
void test_visitImportDirective_withCombinators() {
ShowCombinator combinator = AstFactory.showCombinator2(["A", "B", "C"]);
ImportDirective directive =
AstFactory.importDirective3(null, null, [combinator]);
LibraryElementImpl library =
ElementFactory.library(_definingLibrary.context, "lib");
TopLevelVariableElementImpl varA =
ElementFactory.topLevelVariableElement2("A");
TopLevelVariableElementImpl varB =
ElementFactory.topLevelVariableElement2("B");
TopLevelVariableElementImpl varC =
ElementFactory.topLevelVariableElement2("C");
CompilationUnitElementImpl unit =
library.definingCompilationUnit as CompilationUnitElementImpl;
unit.accessors = <PropertyAccessorElement>[
varA.getter,
varA.setter,
varB.getter,
varC.setter
];
unit.topLevelVariables = <TopLevelVariableElement>[varA, varB, varC];
directive.element = ElementFactory.importFor(library, null);
_resolveNode(directive);
expect(combinator.shownNames[0].staticElement, same(varA));
expect(combinator.shownNames[1].staticElement, same(varB));
expect(combinator.shownNames[2].staticElement, same(varC));
_listener.assertNoErrors();
}
void test_visitIndexExpression_get() {
ClassElementImpl classA = ElementFactory.classElement2("A");
InterfaceType intType = _typeProvider.intType;
MethodElement getter =
ElementFactory.methodElement("[]", intType, [intType]);
classA.methods = <MethodElement>[getter];
SimpleIdentifier array = AstFactory.identifier3("a");
array.staticType = classA.type;
IndexExpression expression =
AstFactory.indexExpression(array, AstFactory.identifier3("i"));
expect(_resolveIndexExpression(expression), same(getter));
_listener.assertNoErrors();
}
void test_visitIndexExpression_set() {
ClassElementImpl classA = ElementFactory.classElement2("A");
InterfaceType intType = _typeProvider.intType;
MethodElement setter =
ElementFactory.methodElement("[]=", intType, [intType]);
classA.methods = <MethodElement>[setter];
SimpleIdentifier array = AstFactory.identifier3("a");
array.staticType = classA.type;
IndexExpression expression =
AstFactory.indexExpression(array, AstFactory.identifier3("i"));
AstFactory.assignmentExpression(
expression, TokenType.EQ, AstFactory.integer(0));
expect(_resolveIndexExpression(expression), same(setter));
_listener.assertNoErrors();
}
void test_visitInstanceCreationExpression_named() {
ClassElementImpl classA = ElementFactory.classElement2("A");
String constructorName = "a";
ConstructorElement constructor =
ElementFactory.constructorElement2(classA, constructorName);
classA.constructors = <ConstructorElement>[constructor];
ConstructorName name = AstFactory.constructorName(
AstFactory.typeName(classA), constructorName);
name.staticElement = constructor;
InstanceCreationExpression creation =
AstFactory.instanceCreationExpression(Keyword.NEW, name);
_resolveNode(creation);
expect(creation.staticElement, same(constructor));
_listener.assertNoErrors();
}
void test_visitInstanceCreationExpression_unnamed() {
ClassElementImpl classA = ElementFactory.classElement2("A");
String constructorName = null;
ConstructorElement constructor =
ElementFactory.constructorElement2(classA, constructorName);
classA.constructors = <ConstructorElement>[constructor];
ConstructorName name = AstFactory.constructorName(
AstFactory.typeName(classA), constructorName);
name.staticElement = constructor;
InstanceCreationExpression creation =
AstFactory.instanceCreationExpression(Keyword.NEW, name);
_resolveNode(creation);
expect(creation.staticElement, same(constructor));
_listener.assertNoErrors();
}
void test_visitInstanceCreationExpression_unnamed_namedParameter() {
ClassElementImpl classA = ElementFactory.classElement2("A");
String constructorName = null;
ConstructorElementImpl constructor =
ElementFactory.constructorElement2(classA, constructorName);
String parameterName = "a";
ParameterElement parameter = ElementFactory.namedParameter(parameterName);
constructor.parameters = <ParameterElement>[parameter];
classA.constructors = <ConstructorElement>[constructor];
ConstructorName name = AstFactory.constructorName(
AstFactory.typeName(classA), constructorName);
name.staticElement = constructor;
InstanceCreationExpression creation = AstFactory.instanceCreationExpression(
Keyword.NEW, name,
[AstFactory.namedExpression2(parameterName, AstFactory.integer(0))]);
_resolveNode(creation);
expect(creation.staticElement, same(constructor));
expect((creation.argumentList.arguments[
0] as NamedExpression).name.label.staticElement, same(parameter));
_listener.assertNoErrors();
}
void test_visitMethodInvocation() {
InterfaceType numType = _typeProvider.numType;
SimpleIdentifier left = AstFactory.identifier3("i");
left.staticType = numType;
String methodName = "abs";
MethodInvocation invocation = AstFactory.methodInvocation(left, methodName);
_resolveNode(invocation);
expect(invocation.methodName.staticElement,
same(getMethod(numType, methodName)));
_listener.assertNoErrors();
}
void test_visitMethodInvocation_namedParameter() {
ClassElementImpl classA = ElementFactory.classElement2("A");
String methodName = "m";
String parameterName = "p";
MethodElementImpl method = ElementFactory.methodElement(methodName, null);
ParameterElement parameter = ElementFactory.namedParameter(parameterName);
method.parameters = <ParameterElement>[parameter];
classA.methods = <MethodElement>[method];
SimpleIdentifier left = AstFactory.identifier3("i");
left.staticType = classA.type;
MethodInvocation invocation = AstFactory.methodInvocation(left, methodName,
[AstFactory.namedExpression2(parameterName, AstFactory.integer(0))]);
_resolveNode(invocation);
expect(invocation.methodName.staticElement, same(method));
expect((invocation.argumentList.arguments[
0] as NamedExpression).name.label.staticElement, same(parameter));
_listener.assertNoErrors();
}
void test_visitPostfixExpression() {
InterfaceType numType = _typeProvider.numType;
SimpleIdentifier operand = AstFactory.identifier3("i");
operand.staticType = numType;
PostfixExpression expression =
AstFactory.postfixExpression(operand, TokenType.PLUS_PLUS);
_resolveNode(expression);
expect(expression.staticElement, getMethod(numType, "+"));
_listener.assertNoErrors();
}
void test_visitPrefixedIdentifier_dynamic() {
DartType dynamicType = _typeProvider.dynamicType;
SimpleIdentifier target = AstFactory.identifier3("a");
VariableElementImpl variable = ElementFactory.localVariableElement(target);
variable.type = dynamicType;
target.staticElement = variable;
target.staticType = dynamicType;
PrefixedIdentifier identifier =
AstFactory.identifier(target, AstFactory.identifier3("b"));
_resolveNode(identifier);
expect(identifier.staticElement, isNull);
expect(identifier.identifier.staticElement, isNull);
_listener.assertNoErrors();
}
void test_visitPrefixedIdentifier_nonDynamic() {
ClassElementImpl classA = ElementFactory.classElement2("A");
String getterName = "b";
PropertyAccessorElement getter =
ElementFactory.getterElement(getterName, false, _typeProvider.intType);
classA.accessors = <PropertyAccessorElement>[getter];
SimpleIdentifier target = AstFactory.identifier3("a");
VariableElementImpl variable = ElementFactory.localVariableElement(target);
variable.type = classA.type;
target.staticElement = variable;
target.staticType = classA.type;
PrefixedIdentifier identifier =
AstFactory.identifier(target, AstFactory.identifier3(getterName));
_resolveNode(identifier);
expect(identifier.staticElement, same(getter));
expect(identifier.identifier.staticElement, same(getter));
_listener.assertNoErrors();
}
void test_visitPrefixedIdentifier_staticClassMember_getter() {
ClassElementImpl classA = ElementFactory.classElement2("A");
// set accessors
String propName = "b";
PropertyAccessorElement getter =
ElementFactory.getterElement(propName, false, _typeProvider.intType);
PropertyAccessorElement setter =
ElementFactory.setterElement(propName, false, _typeProvider.intType);
classA.accessors = <PropertyAccessorElement>[getter, setter];
// prepare "A.m"
SimpleIdentifier target = AstFactory.identifier3("A");
target.staticElement = classA;
target.staticType = classA.type;
PrefixedIdentifier identifier =
AstFactory.identifier(target, AstFactory.identifier3(propName));
// resolve
_resolveNode(identifier);
expect(identifier.staticElement, same(getter));
expect(identifier.identifier.staticElement, same(getter));
_listener.assertNoErrors();
}
void test_visitPrefixedIdentifier_staticClassMember_method() {
ClassElementImpl classA = ElementFactory.classElement2("A");
// set methods
String propName = "m";
MethodElement method =
ElementFactory.methodElement("m", _typeProvider.intType);
classA.methods = <MethodElement>[method];
// prepare "A.m"
SimpleIdentifier target = AstFactory.identifier3("A");
target.staticElement = classA;
target.staticType = classA.type;
PrefixedIdentifier identifier =
AstFactory.identifier(target, AstFactory.identifier3(propName));
AstFactory.assignmentExpression(
identifier, TokenType.EQ, AstFactory.nullLiteral());
// resolve
_resolveNode(identifier);
expect(identifier.staticElement, same(method));
expect(identifier.identifier.staticElement, same(method));
_listener.assertNoErrors();
}
void test_visitPrefixedIdentifier_staticClassMember_setter() {
ClassElementImpl classA = ElementFactory.classElement2("A");
// set accessors
String propName = "b";
PropertyAccessorElement getter =
ElementFactory.getterElement(propName, false, _typeProvider.intType);
PropertyAccessorElement setter =
ElementFactory.setterElement(propName, false, _typeProvider.intType);
classA.accessors = <PropertyAccessorElement>[getter, setter];
// prepare "A.b = null"
SimpleIdentifier target = AstFactory.identifier3("A");
target.staticElement = classA;
target.staticType = classA.type;
PrefixedIdentifier identifier =
AstFactory.identifier(target, AstFactory.identifier3(propName));
AstFactory.assignmentExpression(
identifier, TokenType.EQ, AstFactory.nullLiteral());
// resolve
_resolveNode(identifier);
expect(identifier.staticElement, same(setter));
expect(identifier.identifier.staticElement, same(setter));
_listener.assertNoErrors();
}
void test_visitPrefixExpression() {
InterfaceType numType = _typeProvider.numType;
SimpleIdentifier operand = AstFactory.identifier3("i");
operand.staticType = numType;
PrefixExpression expression =
AstFactory.prefixExpression(TokenType.PLUS_PLUS, operand);
_resolveNode(expression);
expect(expression.staticElement, getMethod(numType, "+"));
_listener.assertNoErrors();
}
void test_visitPropertyAccess_getter_identifier() {
ClassElementImpl classA = ElementFactory.classElement2("A");
String getterName = "b";
PropertyAccessorElement getter =
ElementFactory.getterElement(getterName, false, _typeProvider.intType);
classA.accessors = <PropertyAccessorElement>[getter];
SimpleIdentifier target = AstFactory.identifier3("a");
target.staticType = classA.type;
PropertyAccess access = AstFactory.propertyAccess2(target, getterName);
_resolveNode(access);
expect(access.propertyName.staticElement, same(getter));
_listener.assertNoErrors();
}
void test_visitPropertyAccess_getter_super() {
//
// class A {
// int get b;
// }
// class B {
// ... super.m ...
// }
//
ClassElementImpl classA = ElementFactory.classElement2("A");
String getterName = "b";
PropertyAccessorElement getter =
ElementFactory.getterElement(getterName, false, _typeProvider.intType);
classA.accessors = <PropertyAccessorElement>[getter];
SuperExpression target = AstFactory.superExpression();
target.staticType = ElementFactory.classElement("B", classA.type).type;
PropertyAccess access = AstFactory.propertyAccess2(target, getterName);
AstFactory.methodDeclaration2(null, null, null, null,
AstFactory.identifier3("m"), AstFactory.formalParameterList(),
AstFactory.expressionFunctionBody(access));
_resolveNode(access);
expect(access.propertyName.staticElement, same(getter));
_listener.assertNoErrors();
}
void test_visitPropertyAccess_setter_this() {
ClassElementImpl classA = ElementFactory.classElement2("A");
String setterName = "b";
PropertyAccessorElement setter =
ElementFactory.setterElement(setterName, false, _typeProvider.intType);
classA.accessors = <PropertyAccessorElement>[setter];
ThisExpression target = AstFactory.thisExpression();
target.staticType = classA.type;
PropertyAccess access = AstFactory.propertyAccess2(target, setterName);
AstFactory.assignmentExpression(
access, TokenType.EQ, AstFactory.integer(0));
_resolveNode(access);
expect(access.propertyName.staticElement, same(setter));
_listener.assertNoErrors();
}
void test_visitSimpleIdentifier_classScope() {
InterfaceType doubleType = _typeProvider.doubleType;
String fieldName = "NAN";
SimpleIdentifier node = AstFactory.identifier3(fieldName);
_resolveInClass(node, doubleType.element);
expect(node.staticElement, getGetter(doubleType, fieldName));
_listener.assertNoErrors();
}
void test_visitSimpleIdentifier_dynamic() {
SimpleIdentifier node = AstFactory.identifier3("dynamic");
_resolveIdentifier(node);
expect(node.staticElement, same(_typeProvider.dynamicType.element));
expect(node.staticType, same(_typeProvider.typeType));
_listener.assertNoErrors();
}
void test_visitSimpleIdentifier_lexicalScope() {
SimpleIdentifier node = AstFactory.identifier3("i");
VariableElementImpl element = ElementFactory.localVariableElement(node);
expect(_resolveIdentifier(node, [element]), same(element));
_listener.assertNoErrors();
}
void test_visitSimpleIdentifier_lexicalScope_field_setter() {
InterfaceType intType = _typeProvider.intType;
ClassElementImpl classA = ElementFactory.classElement2("A");
String fieldName = "a";
FieldElement field =
ElementFactory.fieldElement(fieldName, false, false, false, intType);
classA.fields = <FieldElement>[field];
classA.accessors = <PropertyAccessorElement>[field.getter, field.setter];
SimpleIdentifier node = AstFactory.identifier3(fieldName);
AstFactory.assignmentExpression(node, TokenType.EQ, AstFactory.integer(0));
_resolveInClass(node, classA);
Element element = node.staticElement;
EngineTestCase.assertInstanceOf((obj) => obj is PropertyAccessorElement,
PropertyAccessorElement, element);
expect((element as PropertyAccessorElement).isSetter, isTrue);
_listener.assertNoErrors();
}
void test_visitSuperConstructorInvocation() {
ClassElementImpl superclass = ElementFactory.classElement2("A");
ConstructorElementImpl superConstructor =
ElementFactory.constructorElement2(superclass, null);
superclass.constructors = <ConstructorElement>[superConstructor];
ClassElementImpl subclass =
ElementFactory.classElement("B", superclass.type);
ConstructorElementImpl subConstructor =
ElementFactory.constructorElement2(subclass, null);
subclass.constructors = <ConstructorElement>[subConstructor];
SuperConstructorInvocation invocation =
AstFactory.superConstructorInvocation();
_resolveInClass(invocation, subclass);
expect(invocation.staticElement, superConstructor);
_listener.assertNoErrors();
}
void test_visitSuperConstructorInvocation_namedParameter() {
ClassElementImpl superclass = ElementFactory.classElement2("A");
ConstructorElementImpl superConstructor =
ElementFactory.constructorElement2(superclass, null);
String parameterName = "p";
ParameterElement parameter = ElementFactory.namedParameter(parameterName);
superConstructor.parameters = <ParameterElement>[parameter];
superclass.constructors = <ConstructorElement>[superConstructor];
ClassElementImpl subclass =
ElementFactory.classElement("B", superclass.type);
ConstructorElementImpl subConstructor =
ElementFactory.constructorElement2(subclass, null);
subclass.constructors = <ConstructorElement>[subConstructor];
SuperConstructorInvocation invocation = AstFactory
.superConstructorInvocation([
AstFactory.namedExpression2(parameterName, AstFactory.integer(0))
]);
_resolveInClass(invocation, subclass);
expect(invocation.staticElement, superConstructor);
expect((invocation.argumentList.arguments[
0] as NamedExpression).name.label.staticElement, same(parameter));
_listener.assertNoErrors();
}
/**
* Create the resolver used by the tests.
*
* @return the resolver that was created
*/
ElementResolver _createResolver() {
AnalysisContextImpl context = new AnalysisContextImpl();
SourceFactory sourceFactory = new SourceFactory(
[new DartUriResolver(DirectoryBasedDartSdk.defaultSdk)]);
context.sourceFactory = sourceFactory;
FileBasedSource source =
new FileBasedSource.con1(FileUtilities2.createFile("/test.dart"));
CompilationUnitElementImpl definingCompilationUnit =
new CompilationUnitElementImpl("test.dart");
definingCompilationUnit.source = source;
_definingLibrary = ElementFactory.library(context, "test");
_definingLibrary.definingCompilationUnit = definingCompilationUnit;
Library library = new Library(context, _listener, source);
library.libraryElement = _definingLibrary;
_visitor = new ResolverVisitor.con1(library, source, _typeProvider);
try {
return _visitor.elementResolver;
} catch (exception) {
throw new IllegalArgumentException(
"Could not create resolver", exception);
}
}
/**
* Return the element associated with the label of [statement] after the
* resolver has resolved it. [labelElement] is the label element to be
* defined in the statement's label scope, and [labelTarget] is the statement
* the label resolves to.
*/
Element _resolveBreak(BreakStatement statement, LabelElementImpl labelElement,
Statement labelTarget) {
_resolveStatement(statement, labelElement, labelTarget);
return statement.label.staticElement;
}
/**
* Return the element associated with the label [statement] after the
* resolver has resolved it. [labelElement] is the label element to be
* defined in the statement's label scope, and [labelTarget] is the AST node
* the label resolves to.
*
* @param statement the statement to be resolved
* @param labelElement the label element to be defined in the statement's label scope
* @return the element to which the statement's label was resolved
*/
Element _resolveContinue(ContinueStatement statement,
LabelElementImpl labelElement, AstNode labelTarget) {
_resolveStatement(statement, labelElement, labelTarget);
return statement.label.staticElement;
}
/**
* Return the element associated with the given identifier after the resolver has resolved the
* identifier.
*
* @param node the expression to be resolved
* @param definedElements the elements that are to be defined in the scope in which the element is
* being resolved
* @return the element to which the expression was resolved
*/
Element _resolveIdentifier(Identifier node, [List<Element> definedElements]) {
_resolveNode(node, definedElements);
return node.staticElement;
}
/**
* Return the element associated with the given identifier after the resolver has resolved the
* identifier.
*
* @param node the expression to be resolved
* @param enclosingClass the element representing the class enclosing the identifier
* @return the element to which the expression was resolved
*/
void _resolveInClass(AstNode node, ClassElement enclosingClass) {
try {
Scope outerScope = _visitor.nameScope;
try {
_visitor.enclosingClass = enclosingClass;
EnclosedScope innerScope = new ClassScope(
new TypeParameterScope(outerScope, enclosingClass), enclosingClass);
_visitor.nameScope = innerScope;
node.accept(_resolver);
} finally {
_visitor.enclosingClass = null;
_visitor.nameScope = outerScope;
}
} catch (exception) {
throw new IllegalArgumentException("Could not resolve node", exception);
}
}
/**
* Return the element associated with the given expression after the resolver has resolved the
* expression.
*
* @param node the expression to be resolved
* @param definedElements the elements that are to be defined in the scope in which the element is
* being resolved
* @return the element to which the expression was resolved
*/
Element _resolveIndexExpression(IndexExpression node,
[List<Element> definedElements]) {
_resolveNode(node, definedElements);
return node.staticElement;
}
/**
* Return the element associated with the given identifier after the resolver has resolved the
* identifier.
*
* @param node the expression to be resolved
* @param definedElements the elements that are to be defined in the scope in which the element is
* being resolved
* @return the element to which the expression was resolved
*/
void _resolveNode(AstNode node, [List<Element> definedElements]) {
try {
Scope outerScope = _visitor.nameScope;
try {
EnclosedScope innerScope = new EnclosedScope(outerScope);
if (definedElements != null) {
for (Element element in definedElements) {
innerScope.define(element);
}
}
_visitor.nameScope = innerScope;
node.accept(_resolver);
} finally {
_visitor.nameScope = outerScope;
}
} catch (exception) {
throw new IllegalArgumentException("Could not resolve node", exception);
}
}
/**
* Return the element associated with the label of the given statement after the resolver has
* resolved the statement.
*
* @param statement the statement to be resolved
* @param labelElement the label element to be defined in the statement's label scope
* @return the element to which the statement's label was resolved
*/
void _resolveStatement(
Statement statement, LabelElementImpl labelElement, AstNode labelTarget) {
try {
LabelScope outerScope = _visitor.labelScope;
try {
LabelScope innerScope;
if (labelElement == null) {
innerScope = outerScope;
} else {
innerScope = new LabelScope(
outerScope, labelElement.name, labelTarget, labelElement);
}
_visitor.labelScope = innerScope;
statement.accept(_resolver);
} finally {
_visitor.labelScope = outerScope;
}
} catch (exception) {
throw new IllegalArgumentException("Could not resolve node", exception);
}
}
}
@reflectiveTest
class EnclosedScopeTest extends ResolverTestCase {
void test_define_duplicate() {
GatheringErrorListener listener = new GatheringErrorListener();
Scope rootScope =
new Scope_EnclosedScopeTest_test_define_duplicate(listener);
EnclosedScope scope = new EnclosedScope(rootScope);
VariableElement element1 =
ElementFactory.localVariableElement(AstFactory.identifier3("v1"));
VariableElement element2 =
ElementFactory.localVariableElement(AstFactory.identifier3("v1"));
scope.define(element1);
scope.define(element2);
listener.assertErrorsWithSeverities([ErrorSeverity.ERROR]);
}
void test_define_normal() {
GatheringErrorListener listener = new GatheringErrorListener();
Scope rootScope = new Scope_EnclosedScopeTest_test_define_normal(listener);
EnclosedScope outerScope = new EnclosedScope(rootScope);
EnclosedScope innerScope = new EnclosedScope(outerScope);
VariableElement element1 =
ElementFactory.localVariableElement(AstFactory.identifier3("v1"));
VariableElement element2 =
ElementFactory.localVariableElement(AstFactory.identifier3("v2"));
outerScope.define(element1);
innerScope.define(element2);
listener.assertNoErrors();
}
}
@reflectiveTest
class ErrorResolverTest extends ResolverTestCase {
void test_breakLabelOnSwitchMember() {
Source source = addSource(r'''
class A {
void m(int i) {
switch (i) {
l: case 0:
break;
case 1:
break l;
}
}
}''');
resolve(source);
assertErrors(source, [ResolverErrorCode.BREAK_LABEL_ON_SWITCH_MEMBER]);
verify([source]);
}
void test_continueLabelOnSwitch() {
Source source = addSource(r'''
class A {
void m(int i) {
l: switch (i) {
case 0:
continue l;
}
}
}''');
resolve(source);
assertErrors(source, [ResolverErrorCode.CONTINUE_LABEL_ON_SWITCH]);
verify([source]);
}
void test_enclosingElement_invalidLocalFunction() {
Source source = addSource(r'''
class C {
C() {
int get x => 0;
}
}''');
LibraryElement library = resolve(source);
expect(library, isNotNull);
var unit = library.definingCompilationUnit;
expect(unit, isNotNull);
var types = unit.types;
expect(types, isNotNull);
expect(types, hasLength(1));
var type = types[0];
expect(type, isNotNull);
var constructors = type.constructors;
expect(constructors, isNotNull);
expect(constructors, hasLength(1));
ConstructorElement constructor = constructors[0];
expect(constructor, isNotNull);
List<FunctionElement> functions = constructor.functions;
expect(functions, isNotNull);
expect(functions, hasLength(1));
expect(functions[0].enclosingElement, constructor);
assertErrors(source, [ParserErrorCode.GETTER_IN_FUNCTION]);
}
}
@reflectiveTest
class HintCodeTest extends ResolverTestCase {
void fail_deadCode_statementAfterRehrow() {
Source source = addSource(r'''
f() {
try {
var one = 1;
} catch (e) {
rethrow;
var two = 2;
}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void fail_deadCode_statementAfterThrow() {
Source source = addSource(r'''
f() {
var one = 1;
throw 'Stop here';
var two = 2;
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void fail_isInt() {
Source source = addSource("var v = 1 is int;");
resolve(source);
assertErrors(source, [HintCode.IS_INT]);
verify([source]);
}
void fail_isNotInt() {
Source source = addSource("var v = 1 is! int;");
resolve(source);
assertErrors(source, [HintCode.IS_NOT_INT]);
verify([source]);
}
void fail_overrideEqualsButNotHashCode() {
Source source = addSource(r'''
class A {
bool operator ==(x) {}
}''');
resolve(source);
assertErrors(source, [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE]);
verify([source]);
}
void fail_unusedImport_as_equalPrefixes() {
// See todo at ImportsVerifier.prefixElementMap.
Source source = addSource(r'''
library L;
import 'lib1.dart' as one;
import 'lib2.dart' as one;
one.A a;''');
Source source2 = addNamedSource("/lib1.dart", r'''
library lib1;
class A {}''');
Source source3 = addNamedSource("/lib2.dart", r'''
library lib2;
class B {}''');
resolve(source);
assertErrors(source, [HintCode.UNUSED_IMPORT]);
assertNoErrors(source2);
assertNoErrors(source3);
verify([source, source2, source3]);
}
void test_argumentTypeNotAssignable_functionType() {
Source source = addSource(r'''
m() {
var a = new A();
a.n(() => 0);
}
class A {
n(void f(int i)) {}
}''');
resolve(source);
assertErrors(source, [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]);
verify([source]);
}
void test_argumentTypeNotAssignable_message() {
// The implementation of HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE assumes that
// StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE has the same message.
expect(StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE.message,
HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE.message);
}
void test_argumentTypeNotAssignable_type() {
Source source = addSource(r'''
m() {
var i = '';
n(i);
}
n(int i) {}''');
resolve(source);
assertErrors(source, [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]);
verify([source]);
}
void test_deadCode_deadBlock_conditionalElse() {
Source source = addSource(r'''
f() {
true ? 1 : 2;
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_deadBlock_conditionalElse_nested() {
// test that a dead else-statement can't generate additional violations
Source source = addSource(r'''
f() {
true ? true : false && false;
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_deadBlock_conditionalIf() {
Source source = addSource(r'''
f() {
false ? 1 : 2;
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_deadBlock_conditionalIf_nested() {
// test that a dead then-statement can't generate additional violations
Source source = addSource(r'''
f() {
false ? false && false : true;
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_deadBlock_else() {
Source source = addSource(r'''
f() {
if(true) {} else {}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_deadBlock_else_nested() {
// test that a dead else-statement can't generate additional violations
Source source = addSource(r'''
f() {
if(true) {} else {if (false) {}}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_deadBlock_if() {
Source source = addSource(r'''
f() {
if(false) {}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_deadBlock_if_nested() {
// test that a dead then-statement can't generate additional violations
Source source = addSource(r'''
f() {
if(false) {if(false) {}}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_deadBlock_while() {
Source source = addSource(r'''
f() {
while(false) {}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_deadBlock_while_nested() {
// test that a dead while body can't generate additional violations
Source source = addSource(r'''
f() {
while(false) {if(false) {}}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_deadCatch_catchFollowingCatch() {
Source source = addSource(r'''
class A {}
f() {
try {} catch (e) {} catch (e) {}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH]);
verify([source]);
}
void test_deadCode_deadCatch_catchFollowingCatch_nested() {
// test that a dead catch clause can't generate additional violations
Source source = addSource(r'''
class A {}
f() {
try {} catch (e) {} catch (e) {if(false) {}}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH]);
verify([source]);
}
void test_deadCode_deadCatch_catchFollowingCatch_object() {
Source source = addSource(r'''
f() {
try {} on Object catch (e) {} catch (e) {}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH]);
verify([source]);
}
void test_deadCode_deadCatch_catchFollowingCatch_object_nested() {
// test that a dead catch clause can't generate additional violations
Source source = addSource(r'''
f() {
try {} on Object catch (e) {} catch (e) {if(false) {}}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH]);
verify([source]);
}
void test_deadCode_deadCatch_onCatchSubtype() {
Source source = addSource(r'''
class A {}
class B extends A {}
f() {
try {} on A catch (e) {} on B catch (e) {}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE_ON_CATCH_SUBTYPE]);
verify([source]);
}
void test_deadCode_deadCatch_onCatchSubtype_nested() {
// test that a dead catch clause can't generate additional violations
Source source = addSource(r'''
class A {}
class B extends A {}
f() {
try {} on A catch (e) {} on B catch (e) {if(false) {}}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE_ON_CATCH_SUBTYPE]);
verify([source]);
}
void test_deadCode_deadOperandLHS_and() {
Source source = addSource(r'''
f() {
bool b = false && false;
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_deadOperandLHS_and_nested() {
Source source = addSource(r'''
f() {
bool b = false && (false && false);
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_deadOperandLHS_or() {
Source source = addSource(r'''
f() {
bool b = true || true;
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_deadOperandLHS_or_nested() {
Source source = addSource(r'''
f() {
bool b = true || (false && false);
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_statementAfterBreak_inDefaultCase() {
Source source = addSource(r'''
f(v) {
switch(v) {
case 1:
default:
break;
var a;
}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_statementAfterBreak_inForEachStatement() {
Source source = addSource(r'''
f() {
var list;
for(var l in list) {
break;
var a;
}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_statementAfterBreak_inForStatement() {
Source source = addSource(r'''
f() {
for(;;) {
break;
var a;
}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_statementAfterBreak_inSwitchCase() {
Source source = addSource(r'''
f(v) {
switch(v) {
case 1:
break;
var a;
}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_statementAfterBreak_inWhileStatement() {
Source source = addSource(r'''
f(v) {
while(v) {
break;
var a;
}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_statementAfterContinue_inForEachStatement() {
Source source = addSource(r'''
f() {
var list;
for(var l in list) {
continue;
var a;
}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_statementAfterContinue_inForStatement() {
Source source = addSource(r'''
f() {
for(;;) {
continue;
var a;
}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_statementAfterContinue_inWhileStatement() {
Source source = addSource(r'''
f(v) {
while(v) {
continue;
var a;
}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_statementAfterReturn_function() {
Source source = addSource(r'''
f() {
var one = 1;
return;
var two = 2;
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_statementAfterReturn_ifStatement() {
Source source = addSource(r'''
f(bool b) {
if(b) {
var one = 1;
return;
var two = 2;
}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_statementAfterReturn_method() {
Source source = addSource(r'''
class A {
m() {
var one = 1;
return;
var two = 2;
}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_statementAfterReturn_nested() {
Source source = addSource(r'''
f() {
var one = 1;
return;
if(false) {}
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deadCode_statementAfterReturn_twoReturns() {
Source source = addSource(r'''
f() {
var one = 1;
return;
var two = 2;
return;
var three = 3;
}''');
resolve(source);
assertErrors(source, [HintCode.DEAD_CODE]);
verify([source]);
}
void test_deprecatedAnnotationUse_assignment() {
Source source = addSource(r'''
class A {
@deprecated
A operator+(A a) { return a; }
}
f(A a) {
A b;
a += b;
}''');
resolve(source);
assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
verify([source]);
}
void test_deprecatedAnnotationUse_Deprecated() {
Source source = addSource(r'''
class A {
@Deprecated('0.9')
m() {}
n() {m();}
}''');
resolve(source);
assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
verify([source]);
}
void test_deprecatedAnnotationUse_deprecated() {
Source source = addSource(r'''
class A {
@deprecated
m() {}
n() {m();}
}''');
resolve(source);
assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
verify([source]);
}
void test_deprecatedAnnotationUse_export() {
Source source = addSource("export 'deprecated_library.dart';");
addNamedSource("/deprecated_library.dart", r'''
@deprecated
library deprecated_library;
class A {}''');
resolve(source);
assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
verify([source]);
}
void test_deprecatedAnnotationUse_getter() {
Source source = addSource(r'''
class A {
@deprecated
get m => 1;
}
f(A a) {
return a.m;
}''');
resolve(source);
assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
verify([source]);
}
void test_deprecatedAnnotationUse_import() {
Source source = addSource(r'''
import 'deprecated_library.dart';
f(A a) {}''');
addNamedSource("/deprecated_library.dart", r'''
@deprecated
library deprecated_library;
class A {}''');
resolve(source);
assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
verify([source]);
}
void test_deprecatedAnnotationUse_indexExpression() {
Source source = addSource(r'''
class A {
@deprecated
operator[](int i) {}
}
f(A a) {
return a[1];
}''');
resolve(source);
assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
verify([source]);
}
void test_deprecatedAnnotationUse_instanceCreation() {
Source source = addSource(r'''
class A {
@deprecated
A(int i) {}
}
f() {
A a = new A(1);
}''');
resolve(source);
assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
verify([source]);
}
void test_deprecatedAnnotationUse_instanceCreation_namedConstructor() {
Source source = addSource(r'''
class A {
@deprecated
A.named(int i) {}
}
f() {
A a = new A.named(1);
}''');
resolve(source);
assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
verify([source]);
}
void test_deprecatedAnnotationUse_operator() {
Source source = addSource(r'''
class A {
@deprecated
operator+(A a) {}
}
f(A a) {
A b;
return a + b;
}''');
resolve(source);
assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
verify([source]);
}
void test_deprecatedAnnotationUse_setter() {
Source source = addSource(r'''
class A {
@deprecated
set s(v) {}
}
f(A a) {
return a.s = 1;
}''');
resolve(source);
assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
verify([source]);
}
void test_deprecatedAnnotationUse_superConstructor() {
Source source = addSource(r'''
class A {
@deprecated
A() {}
}
class B extends A {
B() : super() {}
}''');
resolve(source);
assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
verify([source]);
}
void test_deprecatedAnnotationUse_superConstructor_namedConstructor() {
Source source = addSource(r'''
class A {
@deprecated
A.named() {}
}
class B extends A {
B() : super.named() {}
}''');
resolve(source);
assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
verify([source]);
}
void test_divisionOptimization_double() {
Source source = addSource(r'''
f(double x, double y) {
var v = (x / y).toInt();
}''');
resolve(source);
assertErrors(source, [HintCode.DIVISION_OPTIMIZATION]);
verify([source]);
}
void test_divisionOptimization_int() {
Source source = addSource(r'''
f(int x, int y) {
var v = (x / y).toInt();
}''');
resolve(source);
assertErrors(source, [HintCode.DIVISION_OPTIMIZATION]);
verify([source]);
}
void test_divisionOptimization_propagatedType() {
// Tests the propagated type information of the '/' method
Source source = addSource(r'''
f(x, y) {
x = 1;
y = 1;
var v = (x / y).toInt();
}''');
resolve(source);
assertErrors(source, [HintCode.DIVISION_OPTIMIZATION]);
verify([source]);
}
void test_divisionOptimization_wrappedBinaryExpression() {
Source source = addSource(r'''
f(int x, int y) {
var v = (((x / y))).toInt();
}''');
resolve(source);
assertErrors(source, [HintCode.DIVISION_OPTIMIZATION]);
verify([source]);
}
void test_duplicateImport() {
Source source = addSource(r'''
library L;
import 'lib1.dart';
import 'lib1.dart';
A a;''');
addNamedSource("/lib1.dart", r'''
library lib1;
class A {}''');
resolve(source);
assertErrors(source, [HintCode.DUPLICATE_IMPORT]);
verify([source]);
}
void test_duplicateImport2() {
Source source = addSource(r'''
library L;
import 'lib1.dart';
import 'lib1.dart';
import 'lib1.dart';
A a;''');
addNamedSource("/lib1.dart", r'''
library lib1;
class A {}''');
resolve(source);
assertErrors(
source, [HintCode.DUPLICATE_IMPORT, HintCode.DUPLICATE_IMPORT]);
verify([source]);
}
void test_duplicateImport3() {
Source source = addSource(r'''