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

Unified Diff: packages/analyzer/test/generated/resolver_test.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: packages/analyzer/test/generated/resolver_test.dart
diff --git a/packages/analyzer/test/generated/resolver_test.dart b/packages/analyzer/test/generated/resolver_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..13391621d600e696f99fcba19c1de5047d8cae25
--- /dev/null
+++ b/packages/analyzer/test/generated/resolver_test.dart
@@ -0,0 +1,14862 @@
+// 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/context/context.dart' as newContext;
+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 '../utils.dart';
+import 'test_support.dart';
+
+main() {
+ initializeTestEnvironment();
+ runReflectiveTests(AnalysisDeltaTest);
+ runReflectiveTests(ChangeSetTest);
+ runReflectiveTests(EnclosedScopeTest);
+ runReflectiveTests(LibraryImportScopeTest);
+ runReflectiveTests(LibraryScopeTest);
+ runReflectiveTests(ScopeTest);
+ runReflectiveTests(ElementResolverTest);
+ runReflectiveTests(InheritanceManagerTest);
+ if (!AnalysisEngine.instance.useTaskModel) {
+ runReflectiveTests(LibraryElementBuilderTest);
+ }
+ if (!AnalysisEngine.instance.useTaskModel) {
+ runReflectiveTests(LibraryResolver2Test);
+ }
+ if (!AnalysisEngine.instance.useTaskModel) {
+ 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);
+ runReflectiveTests(StrongModeStaticTypeAnalyzer2Test);
+ runReflectiveTests(StrongModeTypePropagationTest);
+}
+
+/**
+ * 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 context that was created.
+ */
+ static InternalAnalysisContext contextWithCore() {
+ if (AnalysisEngine.instance.useTaskModel) {
+ NewAnalysisContextForTests context = new NewAnalysisContextForTests();
+ return initContextWithCore(context);
+ }
+ AnalysisContextForTests context = new AnalysisContextForTests();
+ return initContextWithCore(context);
+ }
+
+ /**
+ * Create an analysis context that uses the given [options] and has a fake
+ * core library already resolved. Return the context that was created.
+ */
+ static InternalAnalysisContext contextWithCoreAndOptions(
+ AnalysisOptions options) {
+ if (AnalysisEngine.instance.useTaskModel) {
+ NewAnalysisContextForTests context = new NewAnalysisContextForTests();
+ context._internalSetAnalysisOptions(options);
+ return initContextWithCore(context);
+ }
+ 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 InternalAnalysisContext initContextWithCore(
+ InternalAnalysisContext 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.librarySource = coreUnit.source = coreSource;
+ ClassElementImpl proxyClassElement = ElementFactory.classElement2("_Proxy");
+ ClassElement objectClassElement = provider.objectType.element;
+ 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,
+ objectClassElement,
+ proxyClassElement,
+ provider.stackTraceType.element,
+ provider.stringType.element,
+ provider.symbolType.element,
+ provider.typeType.element
+ ];
+ coreUnit.functions = <FunctionElement>[
+ ElementFactory.functionElement3("identical", provider.boolType.element,
+ <ClassElement>[objectClassElement, objectClassElement], null),
+ ElementFactory.functionElement3("print", VoidTypeImpl.instance.element,
+ <ClassElement>[objectClassElement], null)
+ ];
+ TopLevelVariableElement proxyTopLevelVariableElt = ElementFactory
+ .topLevelVariableElement3("proxy", true, false, proxyClassElement.type);
+ ConstTopLevelVariableElementImpl deprecatedTopLevelVariableElt =
+ ElementFactory.topLevelVariableElement3(
+ "deprecated", true, false, provider.deprecatedType);
+ deprecatedTopLevelVariableElt.constantInitializer = AstFactory
+ .instanceCreationExpression2(
+ Keyword.CONST,
+ AstFactory.typeName(provider.deprecatedType.element),
+ [AstFactory.string2('next release')]);
+ 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.librarySource = asyncUnit.source = asyncSource;
+ // Future
+ ClassElementImpl futureElement =
+ ElementFactory.classElement2("Future", ["T"]);
+ // 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.forTypedef(aliasElement);
+ aliasElement.shareTypeParameters(futureElement.typeParameters);
+ aliasType.typeArguments = futureElement.type.typeArguments;
+ DartType futureDynamicType =
+ futureElement.type.substitute4([provider.dynamicType]);
+ MethodElement thenMethod = ElementFactory.methodElementWithParameters(
+ "then", futureElement.type.typeArguments, futureDynamicType, [
+ 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];
+ // StreamSubscription
+ ClassElementImpl streamSubscriptionElement =
+ ElementFactory.classElement2("StreamSubscription", ["T"]);
+ // Stream
+ ClassElementImpl streamElement =
+ ElementFactory.classElement2("Stream", ["T"]);
+ streamElement.constructors = <ConstructorElement>[
+ ElementFactory.constructorElement2(streamElement, null)
+ ];
+ DartType returnType = streamSubscriptionElement.type
+ .substitute4(streamElement.type.typeArguments);
+ List<DartType> parameterTypes = <DartType>[
+ ElementFactory
+ .functionElement3('onData', VoidTypeImpl.instance.element,
+ <TypeDefiningElement>[streamElement.typeParameters[0]], null)
+ .type,
+ ];
+ // TODO(brianwilkerson) This is missing the optional parameters.
+ MethodElementImpl listenMethod =
+ ElementFactory.methodElement('listen', returnType, parameterTypes);
+ streamElement.methods = <MethodElement>[listenMethod];
+
+ asyncUnit.types = <ClassElement>[
+ completerElement,
+ futureElement,
+ streamElement
+ ];
+ 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.librarySource = 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], ClassElement.EMPTY_LIST)
+ ];
+ 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.librarySource = mathUnit.source = mathSource;
+ FunctionElement cosElement = ElementFactory.functionElement3(
+ "cos",
+ provider.doubleType.element,
+ <ClassElement>[provider.numType.element],
+ ClassElement.EMPTY_LIST);
+ TopLevelVariableElement ln10Element = ElementFactory
+ .topLevelVariableElement3("LN10", true, false, provider.doubleType);
+ FunctionElement maxElement = ElementFactory.functionElement3(
+ "max",
+ provider.numType.element,
+ <ClassElement>[provider.numType.element, provider.numType.element],
+ ClassElement.EMPTY_LIST);
+ 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],
+ ClassElement.EMPTY_LIST);
+ FunctionElement sqrtElement = ElementFactory.functionElement3(
+ "sqrt",
+ provider.doubleType.element,
+ <ClassElement>[provider.numType.element],
+ ClassElement.EMPTY_LIST);
+ mathUnit.accessors = <PropertyAccessorElement>[
+ ln10Element.getter,
+ piElement.getter
+ ];
+ mathUnit.functions = <FunctionElement>[
+ cosElement,
+ maxElement,
+ 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;
+ }
+
+ /**
+ * Create an analysis context that has a fake core library already resolved.
+ * Return the context that was created.
+ */
+ static AnalysisContextImpl oldContextWithCore() {
+ AnalysisContextForTests context = new AnalysisContextForTests();
+ return initContextWithCore(context);
+ }
+
+ /**
+ * Create an analysis context that uses the given [options] and has a fake
+ * core library already resolved. Return the context that was created.
+ */
+ static AnalysisContextImpl oldContextWithCoreAndOptions(
+ AnalysisOptions options) {
+ AnalysisContextForTests context = new AnalysisContextForTests();
+ context._internalSetAnalysisOptions(options);
+ return initContextWithCore(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.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].
+ */
+ AnalysisContextHelper([AnalysisOptionsImpl options]) {
+ if (options == null) {
+ options = new AnalysisOptionsImpl();
+ }
+ options.cacheSize = 256;
+ context = AnalysisContextFactory.contextWithCoreAndOptions(options);
+ }
+
+ Source addSource(String path, String code) {
+ Source source = new FileBasedSource(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());''');
+ computeLibrarySourceErrors(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);''');
+ computeLibrarySourceErrors(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());''');
+ computeLibrarySourceErrors(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]);''');
+ computeLibrarySourceErrors(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]);''');
+ computeLibrarySourceErrors(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});''');
+ computeLibrarySourceErrors(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});''');
+ computeLibrarySourceErrors(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});''');
+ computeLibrarySourceErrors(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);''');
+ computeLibrarySourceErrors(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);''');
+ computeLibrarySourceErrors(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);''');
+ computeLibrarySourceErrors(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);''');
+ computeLibrarySourceErrors(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');''');
+ computeLibrarySourceErrors(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());''');
+ computeLibrarySourceErrors(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');''');
+ computeLibrarySourceErrors(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');''');
+ computeLibrarySourceErrors(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());''');
+ computeLibrarySourceErrors(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]);''');
+ computeLibrarySourceErrors(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});''');
+ computeLibrarySourceErrors(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});''');
+ computeLibrarySourceErrors(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();''');
+ computeLibrarySourceErrors(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);''');
+ computeLibrarySourceErrors(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 = '';
+}''');
+ computeLibrarySourceErrors(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');''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [
+ CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH
+ ]);
+ verify([source]);
+ }
+
+ void test_fieldTypeMismatch_generic() {
+ Source source = addSource(r'''
+class C<T> {
+ final T x = y;
+ const C();
+}
+const int y = 1;
+var v = const C<String>();
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [
+ CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
+ StaticTypeWarningCode.INVALID_ASSIGNMENT
+ ]);
+ 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');''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [
+ CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
+ StaticWarningCode.UNDEFINED_CLASS
+ ]);
+ verify([source]);
+ }
+
+ void test_fieldTypeOk_generic() {
+ Source source = addSource(r'''
+class C<T> {
+ final T x = y;
+ const C();
+}
+const int y = 1;
+var v = const C<int>();
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+ 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);''');
+ computeLibrarySourceErrors(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);''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticWarningCode.UNDEFINED_CLASS]);
+ verify([source]);
+ }
+
+ void test_listElementTypeNotAssignable() {
+ Source source = addSource("var v = const <String> [42];");
+ computeLibrarySourceErrors(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};");
+ computeLibrarySourceErrors(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};");
+ computeLibrarySourceErrors(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);''');
+ computeLibrarySourceErrors(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);''');
+ computeLibrarySourceErrors(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);''');
+ computeLibrarySourceErrors(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');''');
+ computeLibrarySourceErrors(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');''');
+ computeLibrarySourceErrors(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');''');
+ computeLibrarySourceErrors(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);''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [
+ CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH
+ ]);
+ verify([source]);
+ }
+
+ void test_topLevelVarAssignable_null() {
+ Source source = addSource("const int x = null;");
+ computeLibrarySourceErrors(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;");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticWarningCode.UNDEFINED_CLASS]);
+ verify([source]);
+ }
+
+ void test_topLevelVarNotAssignable() {
+ Source source = addSource("const int x = 'foo';");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [
+ CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH,
+ StaticTypeWarningCode.INVALID_ASSIGNMENT
+ ]);
+ verify([source]);
+ }
+
+ void test_topLevelVarNotAssignable_undefined() {
+ Source source = addSource("const Unresolved x = 'foo';");
+ computeLibrarySourceErrors(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_visitEnumDeclaration() {
+ ClassElementImpl enumElement =
+ ElementFactory.enumElement(_typeProvider, ('E'));
+ EnumDeclaration enumNode = AstFactory.enumDeclaration2('E', []);
+ Annotation annotationNode =
+ AstFactory.annotation(AstFactory.identifier3('a'));
+ annotationNode.element = ElementFactory.classElement2('A');
+ enumNode.metadata.add(annotationNode);
+ enumNode.name.staticElement = enumElement;
+ _resolveNode(enumNode);
+ List<ElementAnnotation> metadata = enumElement.metadata;
+ expect(metadata, hasLength(1));
+ }
+
+ 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() {
+ InternalAnalysisContext context = AnalysisContextFactory.contextWithCore();
+ FileBasedSource source =
+ new FileBasedSource(FileUtilities2.createFile("/test.dart"));
+ CompilationUnitElementImpl definingCompilationUnit =
+ new CompilationUnitElementImpl("test.dart");
+ definingCompilationUnit.librarySource =
+ definingCompilationUnit.source = source;
+ _definingLibrary = ElementFactory.library(context, "test");
+ _definingLibrary.definingCompilationUnit = definingCompilationUnit;
+ Library library = new Library(context, _listener, source);
+ library.libraryElement = _definingLibrary;
+ _visitor = new ResolverVisitor(
+ library.libraryElement, source, _typeProvider, library.errorListener,
+ nameScope: library.libraryScope,
+ inheritanceManager: library.inheritanceManager);
+ 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;
+ }
+ }
+}''');
+ computeLibrarySourceErrors(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;
+ }
+ }
+}''');
+ computeLibrarySourceErrors(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 = resolve2(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;
+ }
+}''');
+ computeLibrarySourceErrors(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;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEAD_CODE]);
+ verify([source]);
+ }
+
+ void fail_isInt() {
+ Source source = addSource("var v = 1 is int;");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.IS_INT]);
+ verify([source]);
+ }
+
+ void fail_isNotInt() {
+ Source source = addSource("var v = 1 is! int;");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.IS_NOT_INT]);
+ verify([source]);
+ }
+
+ void fail_overrideEqualsButNotHashCode() {
+ Source source = addSource(r'''
+class A {
+ bool operator ==(x) {}
+}''');
+ computeLibrarySourceErrors(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 {}''');
+ computeLibrarySourceErrors(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)) {}
+}''');
+ computeLibrarySourceErrors(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) {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]);
+ verify([source]);
+ }
+
+ void test_deadCode_deadBlock_conditionalElse() {
+ Source source = addSource(r'''
+f() {
+ true ? 1 : 2;
+}''');
+ computeLibrarySourceErrors(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;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEAD_CODE]);
+ verify([source]);
+ }
+
+ void test_deadCode_deadBlock_conditionalIf() {
+ Source source = addSource(r'''
+f() {
+ false ? 1 : 2;
+}''');
+ computeLibrarySourceErrors(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;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEAD_CODE]);
+ verify([source]);
+ }
+
+ void test_deadCode_deadBlock_else() {
+ Source source = addSource(r'''
+f() {
+ if(true) {} else {}
+}''');
+ computeLibrarySourceErrors(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) {}}
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEAD_CODE]);
+ verify([source]);
+ }
+
+ void test_deadCode_deadBlock_if() {
+ Source source = addSource(r'''
+f() {
+ if(false) {}
+}''');
+ computeLibrarySourceErrors(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) {}}
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEAD_CODE]);
+ verify([source]);
+ }
+
+ void test_deadCode_deadBlock_while() {
+ Source source = addSource(r'''
+f() {
+ while(false) {}
+}''');
+ computeLibrarySourceErrors(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) {}}
+}''');
+ computeLibrarySourceErrors(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) {}
+}''');
+ computeLibrarySourceErrors(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) {}}
+}''');
+ computeLibrarySourceErrors(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) {}
+}''');
+ computeLibrarySourceErrors(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) {}}
+}''');
+ computeLibrarySourceErrors(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) {}
+}''');
+ computeLibrarySourceErrors(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) {}}
+}''');
+ computeLibrarySourceErrors(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;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEAD_CODE]);
+ verify([source]);
+ }
+
+ void test_deadCode_deadOperandLHS_and_nested() {
+ Source source = addSource(r'''
+f() {
+ bool b = false && (false && false);
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEAD_CODE]);
+ verify([source]);
+ }
+
+ void test_deadCode_deadOperandLHS_or() {
+ Source source = addSource(r'''
+f() {
+ bool b = true || true;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEAD_CODE]);
+ verify([source]);
+ }
+
+ void test_deadCode_deadOperandLHS_or_nested() {
+ Source source = addSource(r'''
+f() {
+ bool b = true || (false && false);
+}''');
+ computeLibrarySourceErrors(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;
+ }
+}''');
+ computeLibrarySourceErrors(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;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEAD_CODE]);
+ verify([source]);
+ }
+
+ void test_deadCode_statementAfterBreak_inForStatement() {
+ Source source = addSource(r'''
+f() {
+ for(;;) {
+ break;
+ var a;
+ }
+}''');
+ computeLibrarySourceErrors(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;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEAD_CODE]);
+ verify([source]);
+ }
+
+ void test_deadCode_statementAfterBreak_inWhileStatement() {
+ Source source = addSource(r'''
+f(v) {
+ while(v) {
+ break;
+ var a;
+ }
+}''');
+ computeLibrarySourceErrors(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;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEAD_CODE]);
+ verify([source]);
+ }
+
+ void test_deadCode_statementAfterContinue_inForStatement() {
+ Source source = addSource(r'''
+f() {
+ for(;;) {
+ continue;
+ var a;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEAD_CODE]);
+ verify([source]);
+ }
+
+ void test_deadCode_statementAfterContinue_inWhileStatement() {
+ Source source = addSource(r'''
+f(v) {
+ while(v) {
+ continue;
+ var a;
+ }
+}''');
+ computeLibrarySourceErrors(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;
+}''');
+ computeLibrarySourceErrors(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;
+ }
+}''');
+ computeLibrarySourceErrors(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;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEAD_CODE]);
+ verify([source]);
+ }
+
+ void test_deadCode_statementAfterReturn_nested() {
+ Source source = addSource(r'''
+f() {
+ var one = 1;
+ return;
+ if(false) {}
+}''');
+ computeLibrarySourceErrors(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;
+}''');
+ computeLibrarySourceErrors(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;
+}''');
+ computeLibrarySourceErrors(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();}
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DEPRECATED_MEMBER_USE]);
+ verify([source]);
+ }
+
+ void test_deprecatedAnnotationUse_deprecated() {
+ Source source = addSource(r'''
+class A {
+ @deprecated
+ m() {}
+ n() {m();}
+}''');
+ computeLibrarySourceErrors(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 {}''');
+ computeLibrarySourceErrors(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;
+}''');
+ computeLibrarySourceErrors(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 {}''');
+ computeLibrarySourceErrors(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];
+}''');
+ computeLibrarySourceErrors(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);
+}''');
+ computeLibrarySourceErrors(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);
+}''');
+ computeLibrarySourceErrors(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;
+}''');
+ computeLibrarySourceErrors(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;
+}''');
+ computeLibrarySourceErrors(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() {}
+}''');
+ computeLibrarySourceErrors(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() {}
+}''');
+ computeLibrarySourceErrors(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();
+}''');
+ computeLibrarySourceErrors(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();
+}''');
+ computeLibrarySourceErrors(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();
+}''');
+ computeLibrarySourceErrors(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();
+}''');
+ computeLibrarySourceErrors(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 {}''');
+ computeLibrarySourceErrors(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 {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(
+ source, [HintCode.DUPLICATE_IMPORT, HintCode.DUPLICATE_IMPORT]);
+ verify([source]);
+ }
+
+ void test_duplicateImport3() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart' as M show A hide B;
+import 'lib1.dart' as M show A hide B;
+M.A a;''');
+ addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+class A {}
+class B {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.DUPLICATE_IMPORT]);
+ verify([source]);
+ }
+
+ void test_importDeferredLibraryWithLoadFunction() {
+ resolveWithErrors(<String>[
+ r'''
+library lib1;
+loadLibrary() {}
+f() {}''',
+ r'''
+library root;
+import 'lib1.dart' deferred as lib1;
+main() { lib1.f(); }'''
+ ], <ErrorCode>[
+ HintCode.IMPORT_DEFERRED_LIBRARY_WITH_LOAD_FUNCTION
+ ]);
+ }
+
+ void test_invalidAssignment_instanceVariable() {
+ Source source = addSource(r'''
+class A {
+ int x;
+}
+f(var y) {
+ A a;
+ if(y is String) {
+ a.x = y;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.INVALID_ASSIGNMENT]);
+ verify([source]);
+ }
+
+ void test_invalidAssignment_localVariable() {
+ Source source = addSource(r'''
+f(var y) {
+ if(y is String) {
+ int x = y;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.INVALID_ASSIGNMENT]);
+ verify([source]);
+ }
+
+ void test_invalidAssignment_message() {
+ // The implementation of HintCode.INVALID_ASSIGNMENT assumes that
+ // StaticTypeWarningCode.INVALID_ASSIGNMENT has the same message.
+ expect(StaticTypeWarningCode.INVALID_ASSIGNMENT.message,
+ HintCode.INVALID_ASSIGNMENT.message);
+ }
+
+ void test_invalidAssignment_staticVariable() {
+ Source source = addSource(r'''
+class A {
+ static int x;
+}
+f(var y) {
+ if(y is String) {
+ A.x = y;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.INVALID_ASSIGNMENT]);
+ verify([source]);
+ }
+
+ void test_invalidAssignment_variableDeclaration() {
+ // 17971
+ Source source = addSource(r'''
+class Point {
+ final num x, y;
+ Point(this.x, this.y);
+ Point operator +(Point other) {
+ return new Point(x+other.x, y+other.y);
+ }
+}
+main() {
+ var p1 = new Point(0, 0);
+ var p2 = new Point(10, 10);
+ int n = p1 + p2;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.INVALID_ASSIGNMENT]);
+ verify([source]);
+ }
+
+ void test_isDouble() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.dart2jsHint = true;
+ resetWithOptions(options);
+ Source source = addSource("var v = 1 is double;");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.IS_DOUBLE]);
+ verify([source]);
+ }
+
+ void test_isNotDouble() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.dart2jsHint = true;
+ resetWithOptions(options);
+ Source source = addSource("var v = 1 is! double;");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.IS_NOT_DOUBLE]);
+ verify([source]);
+ }
+
+ void test_missingReturn_async() {
+ Source source = addSource('''
+import 'dart:async';
+Future<int> f() async {}
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.MISSING_RETURN]);
+ verify([source]);
+ }
+
+ void test_missingReturn_function() {
+ Source source = addSource("int f() {}");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.MISSING_RETURN]);
+ verify([source]);
+ }
+
+ void test_missingReturn_method() {
+ Source source = addSource(r'''
+class A {
+ int m() {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.MISSING_RETURN]);
+ verify([source]);
+ }
+
+ void test_overrideOnNonOverridingGetter_invalid() {
+ Source source = addSource(r'''
+library dart.core;
+const override = null;
+class A {
+}
+class B extends A {
+ @override
+ int get m => 1;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER]);
+ verify([source]);
+ }
+
+ void test_overrideOnNonOverridingMethod_invalid() {
+ Source source = addSource(r'''
+library dart.core;
+const override = null;
+class A {
+}
+class B extends A {
+ @override
+ int m() => 1;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD]);
+ verify([source]);
+ }
+
+ void test_overrideOnNonOverridingSetter_invalid() {
+ Source source = addSource(r'''
+library dart.core;
+const override = null;
+class A {
+}
+class B extends A {
+ @override
+ set m(int x) {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER]);
+ verify([source]);
+ }
+
+ void test_typeCheck_type_is_Null() {
+ Source source = addSource(r'''
+m(i) {
+ bool b = i is Null;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.TYPE_CHECK_IS_NULL]);
+ verify([source]);
+ }
+
+ void test_typeCheck_type_not_Null() {
+ Source source = addSource(r'''
+m(i) {
+ bool b = i is! Null;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.TYPE_CHECK_IS_NOT_NULL]);
+ verify([source]);
+ }
+
+ void test_undefinedGetter() {
+ Source source = addSource(r'''
+class A {}
+f(var a) {
+ if(a is A) {
+ return a.m;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNDEFINED_GETTER]);
+ }
+
+ void test_undefinedGetter_message() {
+ // The implementation of HintCode.UNDEFINED_SETTER assumes that
+ // UNDEFINED_SETTER in StaticTypeWarningCode and StaticWarningCode are the
+ // same, this verifies that assumption.
+ expect(StaticWarningCode.UNDEFINED_GETTER.message,
+ StaticTypeWarningCode.UNDEFINED_GETTER.message);
+ }
+
+ void test_undefinedMethod() {
+ Source source = addSource(r'''
+f() {
+ var a = 'str';
+ a.notAMethodOnString();
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNDEFINED_METHOD]);
+ }
+
+ void test_undefinedMethod_assignmentExpression() {
+ Source source = addSource(r'''
+class A {}
+class B {
+ f(var a, var a2) {
+ a = new A();
+ a2 = new A();
+ a += a2;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNDEFINED_METHOD]);
+ }
+
+ void test_undefinedOperator_binaryExpression() {
+ Source source = addSource(r'''
+class A {}
+f(var a) {
+ if(a is A) {
+ a + 1;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNDEFINED_OPERATOR]);
+ }
+
+ void test_undefinedOperator_indexBoth() {
+ Source source = addSource(r'''
+class A {}
+f(var a) {
+ if(a is A) {
+ a[0]++;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNDEFINED_OPERATOR]);
+ }
+
+ void test_undefinedOperator_indexGetter() {
+ Source source = addSource(r'''
+class A {}
+f(var a) {
+ if(a is A) {
+ a[0];
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNDEFINED_OPERATOR]);
+ }
+
+ void test_undefinedOperator_indexSetter() {
+ Source source = addSource(r'''
+class A {}
+f(var a) {
+ if(a is A) {
+ a[0] = 1;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNDEFINED_OPERATOR]);
+ }
+
+ void test_undefinedOperator_postfixExpression() {
+ Source source = addSource(r'''
+class A {}
+f(var a) {
+ if(a is A) {
+ a++;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNDEFINED_OPERATOR]);
+ }
+
+ void test_undefinedOperator_prefixExpression() {
+ Source source = addSource(r'''
+class A {}
+f(var a) {
+ if(a is A) {
+ ++a;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNDEFINED_OPERATOR]);
+ }
+
+ void test_undefinedSetter() {
+ Source source = addSource(r'''
+class A {}
+f(var a) {
+ if(a is A) {
+ a.m = 0;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNDEFINED_SETTER]);
+ }
+
+ void test_undefinedSetter_message() {
+ // The implementation of HintCode.UNDEFINED_SETTER assumes that
+ // UNDEFINED_SETTER in StaticTypeWarningCode and StaticWarningCode are the
+ // same, this verifies that assumption.
+ expect(StaticWarningCode.UNDEFINED_SETTER.message,
+ StaticTypeWarningCode.UNDEFINED_SETTER.message);
+ }
+
+ void test_unnecessaryCast_type_supertype() {
+ Source source = addSource(r'''
+m(int i) {
+ var b = i as Object;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNNECESSARY_CAST]);
+ verify([source]);
+ }
+
+ void test_unnecessaryCast_type_type() {
+ Source source = addSource(r'''
+m(num i) {
+ var b = i as num;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNNECESSARY_CAST]);
+ verify([source]);
+ }
+
+ void test_unnecessaryTypeCheck_null_is_Null() {
+ Source source = addSource("bool b = null is Null;");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNNECESSARY_TYPE_CHECK_TRUE]);
+ verify([source]);
+ }
+
+ void test_unnecessaryTypeCheck_null_not_Null() {
+ Source source = addSource("bool b = null is! Null;");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNNECESSARY_TYPE_CHECK_FALSE]);
+ verify([source]);
+ }
+
+ void test_unnecessaryTypeCheck_type_is_dynamic() {
+ Source source = addSource(r'''
+m(i) {
+ bool b = i is dynamic;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNNECESSARY_TYPE_CHECK_TRUE]);
+ verify([source]);
+ }
+
+ void test_unnecessaryTypeCheck_type_is_object() {
+ Source source = addSource(r'''
+m(i) {
+ bool b = i is Object;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNNECESSARY_TYPE_CHECK_TRUE]);
+ verify([source]);
+ }
+
+ void test_unnecessaryTypeCheck_type_not_dynamic() {
+ Source source = addSource(r'''
+m(i) {
+ bool b = i is! dynamic;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNNECESSARY_TYPE_CHECK_FALSE]);
+ verify([source]);
+ }
+
+ void test_unnecessaryTypeCheck_type_not_object() {
+ Source source = addSource(r'''
+m(i) {
+ bool b = i is! Object;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNNECESSARY_TYPE_CHECK_FALSE]);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_isUsed_extends() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {}
+class B extends _A {}
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_isUsed_implements() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {}
+class B implements _A {}
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_isUsed_instanceCreation() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {}
+main() {
+ new _A();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_isUsed_staticFieldAccess() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {
+ static const F = 42;
+}
+main() {
+ _A.F;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_isUsed_staticMethodInvocation() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {
+ static m() {}
+}
+main() {
+ _A.m();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_isUsed_typeArgument() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {}
+main() {
+ var v = new List<_A>();
+ print(v);
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_notUsed_inClassMember() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {
+ static staticMethod() {
+ new _A();
+ }
+ instanceMethod() {
+ new _A();
+ }
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_notUsed_inConstructorName() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {
+ _A() {}
+ _A.named() {}
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_notUsed_isExpression() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {}
+main(p) {
+ if (p is _A) {
+ }
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_notUsed_noReference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {}
+main() {
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_class_notUsed_variableDeclaration() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class _A {}
+main() {
+ _A v;
+ print(v);
+}
+print(x) {}
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_enum_isUsed_fieldReference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+enum _MyEnum {A, B, C}
+main() {
+ print(_MyEnum.B);
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_enum_notUsed_noReference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+enum _MyEnum {A, B, C}
+main() {
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionLocal_isUsed_closure() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+main() {
+ print(() {});
+}
+print(x) {}
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionLocal_isUsed_invocation() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+main() {
+ f() {}
+ f();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionLocal_isUsed_reference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+main() {
+ f() {}
+ print(f);
+}
+print(x) {}
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionLocal_notUsed_noReference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+main() {
+ f() {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionLocal_notUsed_referenceFromItself() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+main() {
+ _f(int p) {
+ _f(p - 1);
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionTop_isUsed_invocation() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+_f() {}
+main() {
+ _f();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionTop_isUsed_reference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+_f() {}
+main() {
+ print(_f);
+}
+print(x) {}
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionTop_notUsed_noReference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+_f() {}
+main() {
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionTop_notUsed_referenceFromItself() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+_f(int p) {
+ _f(p - 1);
+}
+main() {
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionTypeAlias_isUsed_isExpression() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+typedef _F(a, b);
+main(f) {
+ if (f is _F) {
+ print('F');
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionTypeAlias_isUsed_reference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+typedef _F(a, b);
+main(_F f) {
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionTypeAlias_isUsed_typeArgument() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+typedef _F(a, b);
+main() {
+ var v = new List<_F>();
+ print(v);
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionTypeAlias_isUsed_variableDeclaration() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+typedef _F(a, b);
+class A {
+ _F f;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_functionTypeAlias_notUsed_noReference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+typedef _F(a, b);
+main() {
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_getter_isUsed_invocation_implicitThis() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ get _g => null;
+ useGetter() {
+ var v = _g;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_getter_isUsed_invocation_PrefixedIdentifier() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ get _g => null;
+}
+main(A a) {
+ var v = a._g;
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_getter_isUsed_invocation_PropertyAccess() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ get _g => null;
+}
+main() {
+ var v = new A()._g;
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_getter_notUsed_noReference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ get _g => null;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_getter_notUsed_referenceFromItself() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ get _g {
+ return _g;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_isUsed_hasReference_implicitThis() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ _m() {}
+ useMethod() {
+ print(_m);
+ }
+}
+print(x) {}
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_isUsed_hasReference_implicitThis_subclass() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ _m() {}
+ useMethod() {
+ print(_m);
+ }
+}
+class B extends A {
+ _m() {}
+}
+print(x) {}
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_isUsed_hasReference_PrefixedIdentifier() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ _m() {}
+}
+main(A a) {
+ a._m;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_isUsed_hasReference_PropertyAccess() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ _m() {}
+}
+main() {
+ new A()._m;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_isUsed_invocation_implicitThis() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ _m() {}
+ useMethod() {
+ _m();
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_isUsed_invocation_implicitThis_subclass() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ _m() {}
+ useMethod() {
+ _m();
+ }
+}
+class B extends A {
+ _m() {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_isUsed_invocation_MemberElement() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A<T> {
+ _m(T t) {}
+}
+main(A<int> a) {
+ a._m(0);
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_isUsed_invocation_propagated() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ _m() {}
+}
+main() {
+ var a = new A();
+ a._m();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_isUsed_invocation_static() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ _m() {}
+}
+main() {
+ A a = new A();
+ a._m();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_isUsed_invocation_subclass() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ _m() {}
+}
+class B extends A {
+ _m() {}
+}
+main(A a) {
+ a._m();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_isUsed_notPrivate() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ m() {}
+}
+main() {
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_isUsed_staticInvocation() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ static _m() {}
+}
+main() {
+ A._m();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_notUsed_noReference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ static _m() {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_method_notUsed_referenceFromItself() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ static _m(int p) {
+ _m(p - 1);
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_setter_isUsed_invocation_implicitThis() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ set _s(x) {}
+ useSetter() {
+ _s = 42;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_setter_isUsed_invocation_PrefixedIdentifier() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ set _s(x) {}
+}
+main(A a) {
+ a._s = 42;
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_setter_isUsed_invocation_PropertyAccess() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ set _s(x) {}
+}
+main() {
+ new A()._s = 42;
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedElement_setter_notUsed_noReference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ set _s(x) {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedElement_setter_notUsed_referenceFromItself() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ set _s(int x) {
+ if (x > 5) {
+ _s = x - 1;
+ }
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_ELEMENT]);
+ verify([source]);
+ }
+
+ void test_unusedField_isUsed_argument() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ int _f = 0;
+ main() {
+ print(++_f);
+ }
+}
+print(x) {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedField_isUsed_reference_implicitThis() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ int _f;
+ main() {
+ print(_f);
+ }
+}
+print(x) {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedField_isUsed_reference_implicitThis_expressionFunctionBody() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ int _f;
+ m() => _f;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedField_isUsed_reference_implicitThis_subclass() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ int _f;
+ main() {
+ print(_f);
+ }
+}
+class B extends A {
+ int _f;
+}
+print(x) {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedField_isUsed_reference_qualified_propagatedElement() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ int _f;
+}
+main() {
+ var a = new A();
+ print(a._f);
+}
+print(x) {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedField_isUsed_reference_qualified_staticElement() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ int _f;
+}
+main() {
+ A a = new A();
+ print(a._f);
+}
+print(x) {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedField_isUsed_reference_qualified_unresolved() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ int _f;
+}
+main(a) {
+ print(a._f);
+}
+print(x) {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedField_notUsed_compoundAssign() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ int _f;
+ main() {
+ _f += 2;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_FIELD]);
+ verify([source]);
+ }
+
+ void test_unusedField_notUsed_noReference() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ int _f;
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_FIELD]);
+ verify([source]);
+ }
+
+ void test_unusedField_notUsed_postfixExpr() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ int _f = 0;
+ main() {
+ _f++;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_FIELD]);
+ verify([source]);
+ }
+
+ void test_unusedField_notUsed_prefixExpr() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ int _f = 0;
+ main() {
+ ++_f;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_FIELD]);
+ verify([source]);
+ }
+
+ void test_unusedField_notUsed_simpleAssignment() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+class A {
+ int _f;
+ m() {
+ _f = 1;
+ }
+}
+main(A a) {
+ a._f = 2;
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_FIELD]);
+ verify([source]);
+ }
+
+ void test_unusedImport() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart';''');
+ Source source2 = addNamedSource("/lib1.dart", "library lib1;");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_IMPORT]);
+ assertNoErrors(source2);
+ verify([source, source2]);
+ }
+
+ void test_unusedImport_as() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+import 'lib1.dart' as one;
+one.A a;''');
+ Source source2 = addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+class A {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_IMPORT]);
+ assertNoErrors(source2);
+ verify([source, source2]);
+ }
+
+ void test_unusedImport_hide() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+import 'lib1.dart' hide A;
+A a;''');
+ Source source2 = addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+class A {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_IMPORT]);
+ assertNoErrors(source2);
+ verify([source, source2]);
+ }
+
+ void test_unusedImport_show() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart' show A;
+import 'lib1.dart' show B;
+A a;''');
+ Source source2 = addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+class A {}
+class B {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_IMPORT]);
+ assertNoErrors(source2);
+ verify([source, source2]);
+ }
+
+ void test_unusedLocalVariable_inCatch_exception() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+main() {
+ try {
+ } on String catch (exception) {
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_CATCH_CLAUSE]);
+ verify([source]);
+ }
+
+ void test_unusedLocalVariable_inCatch_exception_hasStack() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+main() {
+ try {
+ } catch (exception, stack) {
+ print(stack);
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedLocalVariable_inCatch_exception_noOnClause() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+main() {
+ try {
+ } catch (exception) {
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedLocalVariable_inCatch_stackTrace() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+main() {
+ try {
+ } catch (exception, stackTrace) {
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_CATCH_STACK]);
+ verify([source]);
+ }
+
+ void test_unusedLocalVariable_inCatch_stackTrace_used() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+main() {
+ try {
+ } catch (exception, stackTrace) {
+ print('exception at $stackTrace');
+ }
+}
+print(x) {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedLocalVariable_inFor_underscore_ignored() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+main() {
+ for (var _ in [1,2,3]) {
+ for (var __ in [4,5,6]) {
+ // do something
+ }
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedLocalVariable_inFunction() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+main() {
+ var v = 1;
+ v = 2;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_LOCAL_VARIABLE]);
+ verify([source]);
+ }
+
+ void test_unusedLocalVariable_inMethod() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+class A {
+ foo() {
+ var v = 1;
+ v = 2;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_LOCAL_VARIABLE]);
+ verify([source]);
+ }
+
+ void test_unusedLocalVariable_isInvoked() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+typedef Foo();
+main() {
+ Foo foo;
+ foo();
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedLocalVariable_isRead_notUsed_compoundAssign() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+main() {
+ var v = 1;
+ v += 2;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_LOCAL_VARIABLE]);
+ verify([source]);
+ }
+
+ void test_unusedLocalVariable_isRead_notUsed_postfixExpr() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+main() {
+ var v = 1;
+ v++;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_LOCAL_VARIABLE]);
+ verify([source]);
+ }
+
+ void test_unusedLocalVariable_isRead_notUsed_prefixExpr() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+main() {
+ var v = 1;
+ ++v;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNUSED_LOCAL_VARIABLE]);
+ verify([source]);
+ }
+
+ void test_unusedLocalVariable_isRead_usedArgument() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+main() {
+ var v = 1;
+ print(++v);
+}
+print(x) {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedLocalVariable_isRead_usedInvocationTarget() {
+ enableUnusedLocalVariable = true;
+ Source source = addSource(r'''
+class A {
+ foo() {}
+}
+main() {
+ var a = new A();
+ a.foo();
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_assignmentExpression_function() {
+ Source source = addSource(r'''
+void f() {}
+class A {
+ n() {
+ var a;
+ a = f();
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_assignmentExpression_method() {
+ Source source = addSource(r'''
+class A {
+ void m() {}
+ n() {
+ var a;
+ a = m();
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_inForLoop() {
+ Source source = addSource(r'''
+class A {
+ void m() {}
+ n() {
+ for(var a = m();;) {}
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_variableDeclaration_function() {
+ Source source = addSource(r'''
+void f() {}
+class A {
+ n() {
+ var a = f();
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_variableDeclaration_method() {
+ Source source = addSource(r'''
+class A {
+ void m() {}
+ n() {
+ var a = m();
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_variableDeclaration_method2() {
+ Source source = addSource(r'''
+class A {
+ void m() {}
+ n() {
+ var a = m(), b = m();
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(
+ source, [HintCode.USE_OF_VOID_RESULT, HintCode.USE_OF_VOID_RESULT]);
+ verify([source]);
+ }
+}
+
+@reflectiveTest
+class InheritanceManagerTest extends EngineTestCase {
+ /**
+ * The type provider used to access the types.
+ */
+ TestTypeProvider _typeProvider;
+
+ /**
+ * The library containing the code being resolved.
+ */
+ LibraryElementImpl _definingLibrary;
+
+ /**
+ * The inheritance manager being tested.
+ */
+ InheritanceManager _inheritanceManager;
+
+ /**
+ * The number of members that Object implements (as determined by [TestTypeProvider]).
+ */
+ int _numOfMembersInObject = 0;
+
+ @override
+ void setUp() {
+ _typeProvider = new TestTypeProvider();
+ _inheritanceManager = _createInheritanceManager();
+ InterfaceType objectType = _typeProvider.objectType;
+ _numOfMembersInObject =
+ objectType.methods.length + objectType.accessors.length;
+ }
+
+ void test_getMapOfMembersInheritedFromClasses_accessor_extends() {
+ // class A { int get g; }
+ // class B extends A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String getterName = "g";
+ PropertyAccessorElement getterG =
+ ElementFactory.getterElement(getterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[getterG];
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ MemberMap mapB =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapB.size, _numOfMembersInObject + 1);
+ expect(mapB.get(getterName), same(getterG));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_getMapOfMembersInheritedFromClasses_accessor_implements() {
+ // class A { int get g; }
+ // class B implements A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String getterName = "g";
+ PropertyAccessorElement getterG =
+ ElementFactory.getterElement(getterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[getterG];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.interfaces = <InterfaceType>[classA.type];
+ MemberMap mapB =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapB.size, _numOfMembersInObject);
+ expect(mapB.get(getterName), isNull);
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_getMapOfMembersInheritedFromClasses_accessor_with() {
+ // class A { int get g; }
+ // class B extends Object with A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String getterName = "g";
+ PropertyAccessorElement getterG =
+ ElementFactory.getterElement(getterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[getterG];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.mixins = <InterfaceType>[classA.type];
+ MemberMap mapB =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapB.size, _numOfMembersInObject + 1);
+ expect(mapB.get(getterName), same(getterG));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_getMapOfMembersInheritedFromClasses_implicitExtends() {
+ // class A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ _assertNoErrors(classA);
+ }
+
+ void test_getMapOfMembersInheritedFromClasses_method_extends() {
+ // class A { int g(); }
+ // class B extends A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodM];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.supertype = classA.type;
+ MemberMap mapB =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapB.size, _numOfMembersInObject + 1);
+ expect(mapB.get(methodName), same(methodM));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_getMapOfMembersInheritedFromClasses_method_implements() {
+ // class A { int g(); }
+ // class B implements A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodM];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.interfaces = <InterfaceType>[classA.type];
+ MemberMap mapB =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapB.size, _numOfMembersInObject);
+ expect(mapB.get(methodName), isNull);
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_getMapOfMembersInheritedFromClasses_method_with() {
+ // class A { int g(); }
+ // class B extends Object with A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodM];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.mixins = <InterfaceType>[classA.type];
+ MemberMap mapB =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapB.size, _numOfMembersInObject + 1);
+ expect(mapB.get(methodName), same(methodM));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_getMapOfMembersInheritedFromClasses_method_with_two_mixins() {
+ // class A1 { int m(); }
+ // class A2 { int m(); }
+ // class B extends Object with A1, A2 {}
+ ClassElementImpl classA1 = ElementFactory.classElement2("A1");
+ String methodName = "m";
+ MethodElement methodA1M =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA1.methods = <MethodElement>[methodA1M];
+ ClassElementImpl classA2 = ElementFactory.classElement2("A2");
+ MethodElement methodA2M =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA2.methods = <MethodElement>[methodA2M];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.mixins = <InterfaceType>[classA1.type, classA2.type];
+ MemberMap mapB =
+ _inheritanceManager.getMapOfMembersInheritedFromClasses(classB);
+ expect(mapB.get(methodName), same(methodA2M));
+ _assertNoErrors(classA1);
+ _assertNoErrors(classA2);
+ _assertNoErrors(classB);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_accessor_extends() {
+ // class A { int get g; }
+ // class B extends A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String getterName = "g";
+ PropertyAccessorElement getterG =
+ ElementFactory.getterElement(getterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[getterG];
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ MemberMap mapB =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classB);
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapB.size, _numOfMembersInObject + 1);
+ expect(mapB.get(getterName), same(getterG));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_accessor_implements() {
+ // class A { int get g; }
+ // class B implements A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String getterName = "g";
+ PropertyAccessorElement getterG =
+ ElementFactory.getterElement(getterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[getterG];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.interfaces = <InterfaceType>[classA.type];
+ MemberMap mapB =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classB);
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapB.size, _numOfMembersInObject + 1);
+ expect(mapB.get(getterName), same(getterG));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_accessor_with() {
+ // class A { int get g; }
+ // class B extends Object with A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String getterName = "g";
+ PropertyAccessorElement getterG =
+ ElementFactory.getterElement(getterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[getterG];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.mixins = <InterfaceType>[classA.type];
+ MemberMap mapB =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classB);
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapB.size, _numOfMembersInObject + 1);
+ expect(mapB.get(getterName), same(getterG));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_implicitExtends() {
+ // class A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ _assertNoErrors(classA);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_inconsistentMethodInheritance_getter_method() {
+ // class I1 { int m(); }
+ // class I2 { int get m; }
+ // class A implements I2, I1 {}
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classI1.methods = <MethodElement>[methodM];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ PropertyAccessorElement getter =
+ ElementFactory.getterElement(methodName, false, _typeProvider.intType);
+ classI2.accessors = <PropertyAccessorElement>[getter];
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[classI2.type, classI1.type];
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapA.get(methodName), isNull);
+ _assertErrors(classA,
+ [StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD]);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_inconsistentMethodInheritance_int_str() {
+ // class I1 { int m(); }
+ // class I2 { String m(); }
+ // class A implements I1, I2 {}
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String methodName = "m";
+ MethodElement methodM1 =
+ ElementFactory.methodElement(methodName, null, [_typeProvider.intType]);
+ classI1.methods = <MethodElement>[methodM1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ MethodElement methodM2 = ElementFactory.methodElement(
+ methodName, null, [_typeProvider.stringType]);
+ classI2.methods = <MethodElement>[methodM2];
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapA.get(methodName), isNull);
+ _assertErrors(
+ classA, [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE]);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_inconsistentMethodInheritance_method_getter() {
+ // class I1 { int m(); }
+ // class I2 { int get m; }
+ // class A implements I1, I2 {}
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classI1.methods = <MethodElement>[methodM];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ PropertyAccessorElement getter =
+ ElementFactory.getterElement(methodName, false, _typeProvider.intType);
+ classI2.accessors = <PropertyAccessorElement>[getter];
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapA.get(methodName), isNull);
+ _assertErrors(classA,
+ [StaticWarningCode.INCONSISTENT_METHOD_INHERITANCE_GETTER_AND_METHOD]);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_inconsistentMethodInheritance_numOfRequiredParams() {
+ // class I1 { dynamic m(int, [int]); }
+ // class I2 { dynamic m(int, int, int); }
+ // class A implements I1, I2 {}
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String methodName = "m";
+ MethodElementImpl methodM1 =
+ ElementFactory.methodElement(methodName, _typeProvider.dynamicType);
+ ParameterElementImpl parameter1 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a1"));
+ parameter1.type = _typeProvider.intType;
+ parameter1.parameterKind = ParameterKind.REQUIRED;
+ ParameterElementImpl parameter2 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a2"));
+ parameter2.type = _typeProvider.intType;
+ parameter2.parameterKind = ParameterKind.POSITIONAL;
+ methodM1.parameters = <ParameterElement>[parameter1, parameter2];
+ classI1.methods = <MethodElement>[methodM1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ MethodElementImpl methodM2 =
+ ElementFactory.methodElement(methodName, _typeProvider.dynamicType);
+ ParameterElementImpl parameter3 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a3"));
+ parameter3.type = _typeProvider.intType;
+ parameter3.parameterKind = ParameterKind.REQUIRED;
+ ParameterElementImpl parameter4 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a4"));
+ parameter4.type = _typeProvider.intType;
+ parameter4.parameterKind = ParameterKind.REQUIRED;
+ ParameterElementImpl parameter5 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a5"));
+ parameter5.type = _typeProvider.intType;
+ parameter5.parameterKind = ParameterKind.REQUIRED;
+ methodM2.parameters = <ParameterElement>[
+ parameter3,
+ parameter4,
+ parameter5
+ ];
+ classI2.methods = <MethodElement>[methodM2];
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapA.get(methodName), isNull);
+ _assertErrors(
+ classA, [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE]);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_inconsistentMethodInheritance_str_int() {
+ // class I1 { int m(); }
+ // class I2 { String m(); }
+ // class A implements I2, I1 {}
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String methodName = "m";
+ MethodElement methodM1 = ElementFactory.methodElement(
+ methodName, null, [_typeProvider.stringType]);
+ classI1.methods = <MethodElement>[methodM1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ MethodElement methodM2 =
+ ElementFactory.methodElement(methodName, null, [_typeProvider.intType]);
+ classI2.methods = <MethodElement>[methodM2];
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[classI2.type, classI1.type];
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapA.get(methodName), isNull);
+ _assertErrors(
+ classA, [StaticTypeWarningCode.INCONSISTENT_METHOD_INHERITANCE]);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_method_extends() {
+ // class A { int g(); }
+ // class B extends A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodM];
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ MemberMap mapB =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classB);
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapB.size, _numOfMembersInObject + 1);
+ expect(mapB.get(methodName), same(methodM));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_method_implements() {
+ // class A { int g(); }
+ // class B implements A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodM];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.interfaces = <InterfaceType>[classA.type];
+ MemberMap mapB =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classB);
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapB.size, _numOfMembersInObject + 1);
+ expect(mapB.get(methodName), same(methodM));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_method_with() {
+ // class A { int g(); }
+ // class B extends Object with A {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodM];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.mixins = <InterfaceType>[classA.type];
+ MemberMap mapB =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classB);
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject);
+ expect(mapB.size, _numOfMembersInObject + 1);
+ expect(mapB.get(methodName), same(methodM));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_union_differentNames() {
+ // class I1 { int m1(); }
+ // class I2 { int m2(); }
+ // class A implements I1, I2 {}
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String methodName1 = "m1";
+ MethodElement methodM1 =
+ ElementFactory.methodElement(methodName1, _typeProvider.intType);
+ classI1.methods = <MethodElement>[methodM1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ String methodName2 = "m2";
+ MethodElement methodM2 =
+ ElementFactory.methodElement(methodName2, _typeProvider.intType);
+ classI2.methods = <MethodElement>[methodM2];
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject + 2);
+ expect(mapA.get(methodName1), same(methodM1));
+ expect(mapA.get(methodName2), same(methodM2));
+ _assertNoErrors(classA);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_union_multipleSubtypes_2_getters() {
+ // class I1 { int get g; }
+ // class I2 { num get g; }
+ // class A implements I1, I2 {}
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String accessorName = "g";
+ PropertyAccessorElement getter1 = ElementFactory.getterElement(
+ accessorName, false, _typeProvider.intType);
+ classI1.accessors = <PropertyAccessorElement>[getter1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ PropertyAccessorElement getter2 = ElementFactory.getterElement(
+ accessorName, false, _typeProvider.numType);
+ classI2.accessors = <PropertyAccessorElement>[getter2];
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject + 1);
+ PropertyAccessorElement syntheticAccessor = ElementFactory.getterElement(
+ accessorName, false, _typeProvider.dynamicType);
+ expect(mapA.get(accessorName).type, syntheticAccessor.type);
+ _assertNoErrors(classA);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_union_multipleSubtypes_2_methods() {
+ // class I1 { dynamic m(int); }
+ // class I2 { dynamic m(num); }
+ // class A implements I1, I2 {}
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String methodName = "m";
+ MethodElementImpl methodM1 =
+ ElementFactory.methodElement(methodName, _typeProvider.dynamicType);
+ ParameterElementImpl parameter1 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a0"));
+ parameter1.type = _typeProvider.intType;
+ parameter1.parameterKind = ParameterKind.REQUIRED;
+ methodM1.parameters = <ParameterElement>[parameter1];
+ classI1.methods = <MethodElement>[methodM1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ MethodElementImpl methodM2 =
+ ElementFactory.methodElement(methodName, _typeProvider.dynamicType);
+ ParameterElementImpl parameter2 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a0"));
+ parameter2.type = _typeProvider.numType;
+ parameter2.parameterKind = ParameterKind.REQUIRED;
+ methodM2.parameters = <ParameterElement>[parameter2];
+ classI2.methods = <MethodElement>[methodM2];
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject + 1);
+ MethodElement syntheticMethod = ElementFactory.methodElement(
+ methodName, _typeProvider.dynamicType, [_typeProvider.dynamicType]);
+ expect(mapA.get(methodName).type, syntheticMethod.type);
+ _assertNoErrors(classA);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_union_multipleSubtypes_2_setters() {
+ // class I1 { set s(int); }
+ // class I2 { set s(num); }
+ // class A implements I1, I2 {}
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String accessorName = "s";
+ PropertyAccessorElement setter1 = ElementFactory.setterElement(
+ accessorName, false, _typeProvider.intType);
+ classI1.accessors = <PropertyAccessorElement>[setter1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ PropertyAccessorElement setter2 = ElementFactory.setterElement(
+ accessorName, false, _typeProvider.numType);
+ classI2.accessors = <PropertyAccessorElement>[setter2];
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject + 1);
+ PropertyAccessorElementImpl syntheticAccessor = ElementFactory
+ .setterElement(accessorName, false, _typeProvider.dynamicType);
+ syntheticAccessor.returnType = _typeProvider.dynamicType;
+ expect(mapA.get("$accessorName=").type, syntheticAccessor.type);
+ _assertNoErrors(classA);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_union_multipleSubtypes_3_getters() {
+ // class A {}
+ // class B extends A {}
+ // class C extends B {}
+ // class I1 { A get g; }
+ // class I2 { B get g; }
+ // class I3 { C get g; }
+ // class D implements I1, I2, I3 {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ ClassElementImpl classC = ElementFactory.classElement("C", classB.type);
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String accessorName = "g";
+ PropertyAccessorElement getter1 =
+ ElementFactory.getterElement(accessorName, false, classA.type);
+ classI1.accessors = <PropertyAccessorElement>[getter1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ PropertyAccessorElement getter2 =
+ ElementFactory.getterElement(accessorName, false, classB.type);
+ classI2.accessors = <PropertyAccessorElement>[getter2];
+ ClassElementImpl classI3 = ElementFactory.classElement2("I3");
+ PropertyAccessorElement getter3 =
+ ElementFactory.getterElement(accessorName, false, classC.type);
+ classI3.accessors = <PropertyAccessorElement>[getter3];
+ ClassElementImpl classD = ElementFactory.classElement2("D");
+ classD.interfaces = <InterfaceType>[
+ classI1.type,
+ classI2.type,
+ classI3.type
+ ];
+ MemberMap mapD =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classD);
+ expect(mapD.size, _numOfMembersInObject + 1);
+ PropertyAccessorElement syntheticAccessor = ElementFactory.getterElement(
+ accessorName, false, _typeProvider.dynamicType);
+ expect(mapD.get(accessorName).type, syntheticAccessor.type);
+ _assertNoErrors(classD);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_union_multipleSubtypes_3_methods() {
+ // class A {}
+ // class B extends A {}
+ // class C extends B {}
+ // class I1 { dynamic m(A a); }
+ // class I2 { dynamic m(B b); }
+ // class I3 { dynamic m(C c); }
+ // class D implements I1, I2, I3 {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ ClassElementImpl classC = ElementFactory.classElement("C", classB.type);
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String methodName = "m";
+ MethodElementImpl methodM1 =
+ ElementFactory.methodElement(methodName, _typeProvider.dynamicType);
+ ParameterElementImpl parameter1 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a0"));
+ parameter1.type = classA.type;
+ parameter1.parameterKind = ParameterKind.REQUIRED;
+ methodM1.parameters = <ParameterElement>[parameter1];
+ classI1.methods = <MethodElement>[methodM1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ MethodElementImpl methodM2 =
+ ElementFactory.methodElement(methodName, _typeProvider.dynamicType);
+ ParameterElementImpl parameter2 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a0"));
+ parameter2.type = classB.type;
+ parameter2.parameterKind = ParameterKind.REQUIRED;
+ methodM2.parameters = <ParameterElement>[parameter2];
+ classI2.methods = <MethodElement>[methodM2];
+ ClassElementImpl classI3 = ElementFactory.classElement2("I3");
+ MethodElementImpl methodM3 =
+ ElementFactory.methodElement(methodName, _typeProvider.dynamicType);
+ ParameterElementImpl parameter3 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a0"));
+ parameter3.type = classC.type;
+ parameter3.parameterKind = ParameterKind.REQUIRED;
+ methodM3.parameters = <ParameterElement>[parameter3];
+ classI3.methods = <MethodElement>[methodM3];
+ ClassElementImpl classD = ElementFactory.classElement2("D");
+ classD.interfaces = <InterfaceType>[
+ classI1.type,
+ classI2.type,
+ classI3.type
+ ];
+ MemberMap mapD =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classD);
+ expect(mapD.size, _numOfMembersInObject + 1);
+ MethodElement syntheticMethod = ElementFactory.methodElement(
+ methodName, _typeProvider.dynamicType, [_typeProvider.dynamicType]);
+ expect(mapD.get(methodName).type, syntheticMethod.type);
+ _assertNoErrors(classD);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_union_multipleSubtypes_3_setters() {
+ // class A {}
+ // class B extends A {}
+ // class C extends B {}
+ // class I1 { set s(A); }
+ // class I2 { set s(B); }
+ // class I3 { set s(C); }
+ // class D implements I1, I2, I3 {}
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ ClassElementImpl classC = ElementFactory.classElement("C", classB.type);
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String accessorName = "s";
+ PropertyAccessorElement setter1 =
+ ElementFactory.setterElement(accessorName, false, classA.type);
+ classI1.accessors = <PropertyAccessorElement>[setter1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ PropertyAccessorElement setter2 =
+ ElementFactory.setterElement(accessorName, false, classB.type);
+ classI2.accessors = <PropertyAccessorElement>[setter2];
+ ClassElementImpl classI3 = ElementFactory.classElement2("I3");
+ PropertyAccessorElement setter3 =
+ ElementFactory.setterElement(accessorName, false, classC.type);
+ classI3.accessors = <PropertyAccessorElement>[setter3];
+ ClassElementImpl classD = ElementFactory.classElement2("D");
+ classD.interfaces = <InterfaceType>[
+ classI1.type,
+ classI2.type,
+ classI3.type
+ ];
+ MemberMap mapD =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classD);
+ expect(mapD.size, _numOfMembersInObject + 1);
+ PropertyAccessorElementImpl syntheticAccessor = ElementFactory
+ .setterElement(accessorName, false, _typeProvider.dynamicType);
+ syntheticAccessor.returnType = _typeProvider.dynamicType;
+ expect(mapD.get("$accessorName=").type, syntheticAccessor.type);
+ _assertNoErrors(classD);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_union_oneSubtype_2_methods() {
+ // class I1 { int m(); }
+ // class I2 { int m([int]); }
+ // class A implements I1, I2 {}
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String methodName = "m";
+ MethodElement methodM1 =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classI1.methods = <MethodElement>[methodM1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ MethodElementImpl methodM2 =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ ParameterElementImpl parameter1 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a1"));
+ parameter1.type = _typeProvider.intType;
+ parameter1.parameterKind = ParameterKind.POSITIONAL;
+ methodM2.parameters = <ParameterElement>[parameter1];
+ classI2.methods = <MethodElement>[methodM2];
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[classI1.type, classI2.type];
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject + 1);
+ expect(mapA.get(methodName), same(methodM2));
+ _assertNoErrors(classA);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_union_oneSubtype_3_methods() {
+ // class I1 { int m(); }
+ // class I2 { int m([int]); }
+ // class I3 { int m([int, int]); }
+ // class A implements I1, I2, I3 {}
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String methodName = "m";
+ MethodElementImpl methodM1 =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classI1.methods = <MethodElement>[methodM1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ MethodElementImpl methodM2 =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ ParameterElementImpl parameter1 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a1"));
+ parameter1.type = _typeProvider.intType;
+ parameter1.parameterKind = ParameterKind.POSITIONAL;
+ methodM1.parameters = <ParameterElement>[parameter1];
+ classI2.methods = <MethodElement>[methodM2];
+ ClassElementImpl classI3 = ElementFactory.classElement2("I3");
+ MethodElementImpl methodM3 =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ ParameterElementImpl parameter2 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a2"));
+ parameter2.type = _typeProvider.intType;
+ parameter2.parameterKind = ParameterKind.POSITIONAL;
+ ParameterElementImpl parameter3 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a3"));
+ parameter3.type = _typeProvider.intType;
+ parameter3.parameterKind = ParameterKind.POSITIONAL;
+ methodM3.parameters = <ParameterElement>[parameter2, parameter3];
+ classI3.methods = <MethodElement>[methodM3];
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[
+ classI1.type,
+ classI2.type,
+ classI3.type
+ ];
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject + 1);
+ expect(mapA.get(methodName), same(methodM3));
+ _assertNoErrors(classA);
+ }
+
+ void test_getMapOfMembersInheritedFromInterfaces_union_oneSubtype_4_methods() {
+ // class I1 { int m(); }
+ // class I2 { int m(); }
+ // class I3 { int m([int]); }
+ // class I4 { int m([int, int]); }
+ // class A implements I1, I2, I3, I4 {}
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String methodName = "m";
+ MethodElement methodM1 =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classI1.methods = <MethodElement>[methodM1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ MethodElement methodM2 =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classI2.methods = <MethodElement>[methodM2];
+ ClassElementImpl classI3 = ElementFactory.classElement2("I3");
+ MethodElementImpl methodM3 =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ ParameterElementImpl parameter1 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a1"));
+ parameter1.type = _typeProvider.intType;
+ parameter1.parameterKind = ParameterKind.POSITIONAL;
+ methodM3.parameters = <ParameterElement>[parameter1];
+ classI3.methods = <MethodElement>[methodM3];
+ ClassElementImpl classI4 = ElementFactory.classElement2("I4");
+ MethodElementImpl methodM4 =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ ParameterElementImpl parameter2 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a2"));
+ parameter2.type = _typeProvider.intType;
+ parameter2.parameterKind = ParameterKind.POSITIONAL;
+ ParameterElementImpl parameter3 =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("a3"));
+ parameter3.type = _typeProvider.intType;
+ parameter3.parameterKind = ParameterKind.POSITIONAL;
+ methodM4.parameters = <ParameterElement>[parameter2, parameter3];
+ classI4.methods = <MethodElement>[methodM4];
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[
+ classI1.type,
+ classI2.type,
+ classI3.type,
+ classI4.type
+ ];
+ MemberMap mapA =
+ _inheritanceManager.getMapOfMembersInheritedFromInterfaces(classA);
+ expect(mapA.size, _numOfMembersInObject + 1);
+ expect(mapA.get(methodName), same(methodM4));
+ _assertNoErrors(classA);
+ }
+
+ void test_lookupInheritance_interface_getter() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String getterName = "g";
+ PropertyAccessorElement getterG =
+ ElementFactory.getterElement(getterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[getterG];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.interfaces = <InterfaceType>[classA.type];
+ expect(_inheritanceManager.lookupInheritance(classB, getterName),
+ same(getterG));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupInheritance_interface_method() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodM];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.interfaces = <InterfaceType>[classA.type];
+ expect(_inheritanceManager.lookupInheritance(classB, methodName),
+ same(methodM));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupInheritance_interface_setter() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String setterName = "s";
+ PropertyAccessorElement setterS =
+ ElementFactory.setterElement(setterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[setterS];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.interfaces = <InterfaceType>[classA.type];
+ expect(_inheritanceManager.lookupInheritance(classB, "$setterName="),
+ same(setterS));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupInheritance_interface_staticMember() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ (methodM as MethodElementImpl).static = true;
+ classA.methods = <MethodElement>[methodM];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.interfaces = <InterfaceType>[classA.type];
+ expect(_inheritanceManager.lookupInheritance(classB, methodName), isNull);
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupInheritance_interfaces_infiniteLoop() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[classA.type];
+ expect(_inheritanceManager.lookupInheritance(classA, "name"), isNull);
+ _assertNoErrors(classA);
+ }
+
+ void test_lookupInheritance_interfaces_infiniteLoop2() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classA.interfaces = <InterfaceType>[classB.type];
+ classB.interfaces = <InterfaceType>[classA.type];
+ expect(_inheritanceManager.lookupInheritance(classA, "name"), isNull);
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupInheritance_interfaces_union2() {
+ ClassElementImpl classI1 = ElementFactory.classElement2("I1");
+ String methodName1 = "m1";
+ MethodElement methodM1 =
+ ElementFactory.methodElement(methodName1, _typeProvider.intType);
+ classI1.methods = <MethodElement>[methodM1];
+ ClassElementImpl classI2 = ElementFactory.classElement2("I2");
+ String methodName2 = "m2";
+ MethodElement methodM2 =
+ ElementFactory.methodElement(methodName2, _typeProvider.intType);
+ classI2.methods = <MethodElement>[methodM2];
+ classI2.interfaces = <InterfaceType>[classI1.type];
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.interfaces = <InterfaceType>[classI2.type];
+ expect(_inheritanceManager.lookupInheritance(classA, methodName1),
+ same(methodM1));
+ expect(_inheritanceManager.lookupInheritance(classA, methodName2),
+ same(methodM2));
+ _assertNoErrors(classI1);
+ _assertNoErrors(classI2);
+ _assertNoErrors(classA);
+ }
+
+ void test_lookupInheritance_mixin_getter() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String getterName = "g";
+ PropertyAccessorElement getterG =
+ ElementFactory.getterElement(getterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[getterG];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.mixins = <InterfaceType>[classA.type];
+ expect(_inheritanceManager.lookupInheritance(classB, getterName),
+ same(getterG));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupInheritance_mixin_method() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodM];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.mixins = <InterfaceType>[classA.type];
+ expect(_inheritanceManager.lookupInheritance(classB, methodName),
+ same(methodM));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupInheritance_mixin_setter() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String setterName = "s";
+ PropertyAccessorElement setterS =
+ ElementFactory.setterElement(setterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[setterS];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.mixins = <InterfaceType>[classA.type];
+ expect(_inheritanceManager.lookupInheritance(classB, "$setterName="),
+ same(setterS));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupInheritance_mixin_staticMember() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ (methodM as MethodElementImpl).static = true;
+ classA.methods = <MethodElement>[methodM];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.mixins = <InterfaceType>[classA.type];
+ expect(_inheritanceManager.lookupInheritance(classB, methodName), isNull);
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupInheritance_noMember() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ expect(_inheritanceManager.lookupInheritance(classA, "a"), isNull);
+ _assertNoErrors(classA);
+ }
+
+ void test_lookupInheritance_superclass_getter() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String getterName = "g";
+ PropertyAccessorElement getterG =
+ ElementFactory.getterElement(getterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[getterG];
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ expect(_inheritanceManager.lookupInheritance(classB, getterName),
+ same(getterG));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupInheritance_superclass_infiniteLoop() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ classA.supertype = classA.type;
+ expect(_inheritanceManager.lookupInheritance(classA, "name"), isNull);
+ _assertNoErrors(classA);
+ }
+
+ void test_lookupInheritance_superclass_infiniteLoop2() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classA.supertype = classB.type;
+ classB.supertype = classA.type;
+ expect(_inheritanceManager.lookupInheritance(classA, "name"), isNull);
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupInheritance_superclass_method() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodM];
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ expect(_inheritanceManager.lookupInheritance(classB, methodName),
+ same(methodM));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupInheritance_superclass_setter() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String setterName = "s";
+ PropertyAccessorElement setterS =
+ ElementFactory.setterElement(setterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[setterS];
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ expect(_inheritanceManager.lookupInheritance(classB, "$setterName="),
+ same(setterS));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupInheritance_superclass_staticMember() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ (methodM as MethodElementImpl).static = true;
+ classA.methods = <MethodElement>[methodM];
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ expect(_inheritanceManager.lookupInheritance(classB, methodName), isNull);
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupMember_getter() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String getterName = "g";
+ PropertyAccessorElement getterG =
+ ElementFactory.getterElement(getterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[getterG];
+ expect(_inheritanceManager.lookupMember(classA, getterName), same(getterG));
+ _assertNoErrors(classA);
+ }
+
+ void test_lookupMember_getter_static() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String getterName = "g";
+ PropertyAccessorElement getterG =
+ ElementFactory.getterElement(getterName, true, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[getterG];
+ expect(_inheritanceManager.lookupMember(classA, getterName), isNull);
+ _assertNoErrors(classA);
+ }
+
+ void test_lookupMember_method() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodM];
+ expect(_inheritanceManager.lookupMember(classA, methodName), same(methodM));
+ _assertNoErrors(classA);
+ }
+
+ void test_lookupMember_method_static() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElement methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ (methodM as MethodElementImpl).static = true;
+ classA.methods = <MethodElement>[methodM];
+ expect(_inheritanceManager.lookupMember(classA, methodName), isNull);
+ _assertNoErrors(classA);
+ }
+
+ void test_lookupMember_noMember() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ expect(_inheritanceManager.lookupMember(classA, "a"), isNull);
+ _assertNoErrors(classA);
+ }
+
+ void test_lookupMember_setter() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String setterName = "s";
+ PropertyAccessorElement setterS =
+ ElementFactory.setterElement(setterName, false, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[setterS];
+ expect(_inheritanceManager.lookupMember(classA, "$setterName="),
+ same(setterS));
+ _assertNoErrors(classA);
+ }
+
+ void test_lookupMember_setter_static() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String setterName = "s";
+ PropertyAccessorElement setterS =
+ ElementFactory.setterElement(setterName, true, _typeProvider.intType);
+ classA.accessors = <PropertyAccessorElement>[setterS];
+ expect(_inheritanceManager.lookupMember(classA, setterName), isNull);
+ _assertNoErrors(classA);
+ }
+
+ void test_lookupOverrides_noParentClasses() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElementImpl methodM =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodM];
+ expect(
+ _inheritanceManager.lookupOverrides(classA, methodName), hasLength(0));
+ _assertNoErrors(classA);
+ }
+
+ void test_lookupOverrides_overrideBaseClass() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElementImpl methodMinA =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodMinA];
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ MethodElementImpl methodMinB =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classB.methods = <MethodElement>[methodMinB];
+ List<ExecutableElement> overrides =
+ _inheritanceManager.lookupOverrides(classB, methodName);
+ expect(overrides, unorderedEquals([methodMinA]));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupOverrides_overrideInterface() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElementImpl methodMinA =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodMinA];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ classB.interfaces = <InterfaceType>[classA.type];
+ MethodElementImpl methodMinB =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classB.methods = <MethodElement>[methodMinB];
+ List<ExecutableElement> overrides =
+ _inheritanceManager.lookupOverrides(classB, methodName);
+ expect(overrides, unorderedEquals([methodMinA]));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ }
+
+ void test_lookupOverrides_overrideTwoInterfaces() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ String methodName = "m";
+ MethodElementImpl methodMinA =
+ ElementFactory.methodElement(methodName, _typeProvider.intType);
+ classA.methods = <MethodElement>[methodMinA];
+ ClassElementImpl classB = ElementFactory.classElement2("B");
+ MethodElementImpl methodMinB =
+ ElementFactory.methodElement(methodName, _typeProvider.doubleType);
+ classB.methods = <MethodElement>[methodMinB];
+ ClassElementImpl classC = ElementFactory.classElement2("C");
+ classC.interfaces = <InterfaceType>[classA.type, classB.type];
+ MethodElementImpl methodMinC =
+ ElementFactory.methodElement(methodName, _typeProvider.numType);
+ classC.methods = <MethodElement>[methodMinC];
+ List<ExecutableElement> overrides =
+ _inheritanceManager.lookupOverrides(classC, methodName);
+ expect(overrides, unorderedEquals([methodMinA, methodMinB]));
+ _assertNoErrors(classA);
+ _assertNoErrors(classB);
+ _assertNoErrors(classC);
+ }
+
+ void _assertErrors(ClassElement classElt,
+ [List<ErrorCode> expectedErrorCodes = ErrorCode.EMPTY_LIST]) {
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ HashSet<AnalysisError> actualErrors =
+ _inheritanceManager.getErrors(classElt);
+ if (actualErrors != null) {
+ for (AnalysisError error in actualErrors) {
+ errorListener.onError(error);
+ }
+ }
+ errorListener.assertErrorsWithCodes(expectedErrorCodes);
+ }
+
+ void _assertNoErrors(ClassElement classElt) {
+ _assertErrors(classElt);
+ }
+
+ /**
+ * Create the inheritance manager used by the tests.
+ *
+ * @return the inheritance manager that was created
+ */
+ InheritanceManager _createInheritanceManager() {
+ AnalysisContext context = AnalysisContextFactory.contextWithCore();
+ FileBasedSource source =
+ new FileBasedSource(FileUtilities2.createFile("/test.dart"));
+ CompilationUnitElementImpl definingCompilationUnit =
+ new CompilationUnitElementImpl("test.dart");
+ definingCompilationUnit.librarySource =
+ definingCompilationUnit.source = source;
+ _definingLibrary = ElementFactory.library(context, "test");
+ _definingLibrary.definingCompilationUnit = definingCompilationUnit;
+ return new InheritanceManager(_definingLibrary);
+ }
+}
+
+@reflectiveTest
+class LibraryElementBuilderTest extends EngineTestCase {
+ /**
+ * The analysis context used to analyze sources.
+ */
+ InternalAnalysisContext _context;
+
+ /**
+ * Add a source file to the content provider. The file path should be absolute.
+ *
+ * @param filePath the path of the file being added
+ * @param contents the contents to be returned by the content provider for the specified file
+ * @return the source object representing the added file
+ */
+ Source addSource(String filePath, String contents) {
+ Source source = new FileBasedSource(FileUtilities2.createFile(filePath));
+ _context.setContents(source, contents);
+ return source;
+ }
+
+ @override
+ void setUp() {
+ _context = AnalysisContextFactory.contextWithCore();
+ }
+
+ @override
+ void tearDown() {
+ _context = null;
+ super.tearDown();
+ }
+
+ void test_accessorsAcrossFiles() {
+ Source librarySource = addSource(
+ "/lib.dart",
+ r'''
+library lib;
+part 'first.dart';
+part 'second.dart';''');
+ addSource(
+ "/first.dart",
+ r'''
+part of lib;
+int get V => 0;''');
+ addSource(
+ "/second.dart",
+ r'''
+part of lib;
+void set V(int v) {}''');
+ LibraryElement element = _buildLibrary(librarySource);
+ expect(element, isNotNull);
+ List<CompilationUnitElement> sourcedUnits = element.parts;
+ expect(sourcedUnits, hasLength(2));
+ List<PropertyAccessorElement> firstAccessors = sourcedUnits[0].accessors;
+ expect(firstAccessors, hasLength(1));
+ List<PropertyAccessorElement> secondAccessors = sourcedUnits[1].accessors;
+ expect(secondAccessors, hasLength(1));
+ expect(secondAccessors[0].variable, same(firstAccessors[0].variable));
+ }
+
+ void test_empty() {
+ Source librarySource = addSource("/lib.dart", "library lib;");
+ LibraryElement element = _buildLibrary(librarySource);
+ expect(element, isNotNull);
+ expect(element.name, "lib");
+ expect(element.entryPoint, isNull);
+ expect(element.importedLibraries, hasLength(0));
+ expect(element.imports, hasLength(0));
+ expect(element.library, same(element));
+ expect(element.prefixes, hasLength(0));
+ expect(element.parts, hasLength(0));
+ CompilationUnitElement unit = element.definingCompilationUnit;
+ expect(unit, isNotNull);
+ expect(unit.name, "lib.dart");
+ expect(unit.library, element);
+ expect(unit.accessors, hasLength(0));
+ expect(unit.functions, hasLength(0));
+ expect(unit.functionTypeAliases, hasLength(0));
+ expect(unit.types, hasLength(0));
+ expect(unit.topLevelVariables, hasLength(0));
+ }
+
+ void test_libraryElement_docRange() {
+ String code = r'''
+/// My dart doc.
+library lib;
+
+class A {}''';
+ Source librarySource = addSource("/lib.dart", code);
+ LibraryElement element = _buildLibrary(librarySource);
+ expect(element, isNotNull);
+ SourceRange docRange = element.docRange;
+ expect(docRange, isNotNull);
+ expect(docRange.offset, code.indexOf('/// My dart doc.'));
+ expect(docRange.length, '/// My dart doc.'.length);
+ }
+
+ void test_missingLibraryDirectiveWithPart() {
+ addSource("/a.dart", "part of lib;");
+ Source librarySource = addSource("/lib.dart", "part 'a.dart';");
+ LibraryElement element = _buildLibrary(
+ librarySource, [ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART]);
+ expect(element, isNotNull);
+ }
+
+ void test_missingPartOfDirective() {
+ addSource("/a.dart", "class A {}");
+ Source librarySource = addSource(
+ "/lib.dart",
+ r'''
+library lib;
+
+part 'a.dart';''');
+ LibraryElement element =
+ _buildLibrary(librarySource, [CompileTimeErrorCode.PART_OF_NON_PART]);
+ expect(element, isNotNull);
+ }
+
+ void test_multipleFiles() {
+ Source librarySource = addSource(
+ "/lib.dart",
+ r'''
+library lib;
+part 'first.dart';
+part 'second.dart';
+
+class A {}''');
+ addSource(
+ "/first.dart",
+ r'''
+part of lib;
+class B {}''');
+ addSource(
+ "/second.dart",
+ r'''
+part of lib;
+class C {}''');
+ LibraryElement element = _buildLibrary(librarySource);
+ expect(element, isNotNull);
+ List<CompilationUnitElement> sourcedUnits = element.parts;
+ expect(sourcedUnits, hasLength(2));
+ _assertTypes(element.definingCompilationUnit, ["A"]);
+ if (sourcedUnits[0].name == "first.dart") {
+ _assertTypes(sourcedUnits[0], ["B"]);
+ _assertTypes(sourcedUnits[1], ["C"]);
+ } else {
+ _assertTypes(sourcedUnits[0], ["C"]);
+ _assertTypes(sourcedUnits[1], ["B"]);
+ }
+ }
+
+ void test_singleFile() {
+ Source librarySource = addSource(
+ "/lib.dart",
+ r'''
+/// My dart doc.
+library lib;
+
+class A {}''');
+ LibraryElement element = _buildLibrary(librarySource);
+ expect(element, isNotNull);
+ _assertTypes(element.definingCompilationUnit, ["A"]);
+ }
+
+ /**
+ * Ensure that there are elements representing all of the types in the given array of type names.
+ *
+ * @param unit the compilation unit containing the types
+ * @param typeNames the names of the types that should be found
+ */
+ void _assertTypes(CompilationUnitElement unit, List<String> typeNames) {
+ expect(unit, isNotNull);
+ List<ClassElement> types = unit.types;
+ expect(types, hasLength(typeNames.length));
+ for (ClassElement type in types) {
+ expect(type, isNotNull);
+ String actualTypeName = type.displayName;
+ bool wasExpected = false;
+ for (String expectedTypeName in typeNames) {
+ if (expectedTypeName == actualTypeName) {
+ wasExpected = true;
+ }
+ }
+ if (!wasExpected) {
+ fail("Found unexpected type $actualTypeName");
+ }
+ }
+ }
+
+ /**
+ * Build the element model for the library whose defining compilation unit has the given source.
+ *
+ * @param librarySource the source of the defining compilation unit for the library
+ * @param expectedErrorCodes the errors that are expected to be found while building the element
+ * model
+ * @return the element model that was built for the library
+ * @throws Exception if the element model could not be built
+ */
+ LibraryElement _buildLibrary(Source librarySource,
+ [List<ErrorCode> expectedErrorCodes = ErrorCode.EMPTY_LIST]) {
+ LibraryResolver resolver = new LibraryResolver(_context);
+ LibraryElementBuilder builder = new LibraryElementBuilder(
+ resolver.analysisContext, resolver.errorListener);
+ Library library = resolver.createLibrary(librarySource);
+ LibraryElement element = builder.buildLibrary(library);
+ GatheringErrorListener listener = new GatheringErrorListener();
+ listener.addAll2(resolver.errorListener);
+ listener.assertErrorsWithCodes(expectedErrorCodes);
+ return element;
+ }
+}
+
+@reflectiveTest
+class LibraryImportScopeTest extends ResolverTestCase {
+ void test_conflictingImports() {
+ AnalysisContext context = AnalysisContextFactory.contextWithCore();
+ String typeNameA = "A";
+ String typeNameB = "B";
+ String typeNameC = "C";
+ ClassElement typeA = ElementFactory.classElement2(typeNameA);
+ ClassElement typeB1 = ElementFactory.classElement2(typeNameB);
+ ClassElement typeB2 = ElementFactory.classElement2(typeNameB);
+ ClassElement typeC = ElementFactory.classElement2(typeNameC);
+ LibraryElement importedLibrary1 = createTestLibrary(context, "imported1");
+ (importedLibrary1.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[typeA, typeB1];
+ ImportElementImpl import1 =
+ ElementFactory.importFor(importedLibrary1, null);
+ LibraryElement importedLibrary2 = createTestLibrary(context, "imported2");
+ (importedLibrary2.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[typeB2, typeC];
+ ImportElementImpl import2 =
+ ElementFactory.importFor(importedLibrary2, null);
+ LibraryElementImpl importingLibrary =
+ createTestLibrary(context, "importing");
+ importingLibrary.imports = <ImportElement>[import1, import2];
+ {
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ Scope scope = new LibraryImportScope(importingLibrary, errorListener);
+ expect(scope.lookup(AstFactory.identifier3(typeNameA), importingLibrary),
+ typeA);
+ errorListener.assertNoErrors();
+ expect(scope.lookup(AstFactory.identifier3(typeNameC), importingLibrary),
+ typeC);
+ errorListener.assertNoErrors();
+ Element element =
+ scope.lookup(AstFactory.identifier3(typeNameB), importingLibrary);
+ errorListener.assertErrorsWithCodes([StaticWarningCode.AMBIGUOUS_IMPORT]);
+ EngineTestCase.assertInstanceOf((obj) => obj is MultiplyDefinedElement,
+ MultiplyDefinedElement, element);
+ List<Element> conflictingElements =
+ (element as MultiplyDefinedElement).conflictingElements;
+ expect(conflictingElements, hasLength(2));
+ if (identical(conflictingElements[0], typeB1)) {
+ expect(conflictingElements[1], same(typeB2));
+ } else if (identical(conflictingElements[0], typeB2)) {
+ expect(conflictingElements[1], same(typeB1));
+ } else {
+ expect(conflictingElements[0], same(typeB1));
+ }
+ }
+ {
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ Scope scope = new LibraryImportScope(importingLibrary, errorListener);
+ Identifier identifier = AstFactory.identifier3(typeNameB);
+ AstFactory.methodDeclaration(null, AstFactory.typeName3(identifier), null,
+ null, AstFactory.identifier3("foo"), null);
+ Element element = scope.lookup(identifier, importingLibrary);
+ errorListener.assertErrorsWithCodes([StaticWarningCode.AMBIGUOUS_IMPORT]);
+ EngineTestCase.assertInstanceOf((obj) => obj is MultiplyDefinedElement,
+ MultiplyDefinedElement, element);
+ }
+ }
+
+ void test_creation_empty() {
+ LibraryElement definingLibrary = createDefaultTestLibrary();
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ new LibraryImportScope(definingLibrary, errorListener);
+ }
+
+ void test_creation_nonEmpty() {
+ AnalysisContext context = AnalysisContextFactory.contextWithCore();
+ String importedTypeName = "A";
+ ClassElement importedType =
+ new ClassElementImpl.forNode(AstFactory.identifier3(importedTypeName));
+ LibraryElement importedLibrary = createTestLibrary(context, "imported");
+ (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[importedType];
+ LibraryElementImpl definingLibrary =
+ createTestLibrary(context, "importing");
+ ImportElementImpl importElement = new ImportElementImpl(0);
+ importElement.importedLibrary = importedLibrary;
+ definingLibrary.imports = <ImportElement>[importElement];
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ Scope scope = new LibraryImportScope(definingLibrary, errorListener);
+ expect(
+ scope.lookup(AstFactory.identifier3(importedTypeName), definingLibrary),
+ importedType);
+ }
+
+ void test_getErrorListener() {
+ LibraryElement definingLibrary = createDefaultTestLibrary();
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ LibraryImportScope scope =
+ new LibraryImportScope(definingLibrary, errorListener);
+ expect(scope.errorListener, errorListener);
+ }
+
+ void test_nonConflictingImports_fromSdk() {
+ AnalysisContext context = AnalysisContextFactory.contextWithCore();
+ String typeName = "List";
+ ClassElement type = ElementFactory.classElement2(typeName);
+ LibraryElement importedLibrary = createTestLibrary(context, "lib");
+ (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[type];
+ ImportElementImpl importCore = ElementFactory.importFor(
+ context.getLibraryElement(context.sourceFactory.forUri("dart:core")),
+ null);
+ ImportElementImpl importLib =
+ ElementFactory.importFor(importedLibrary, null);
+ LibraryElementImpl importingLibrary =
+ createTestLibrary(context, "importing");
+ importingLibrary.imports = <ImportElement>[importCore, importLib];
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ Scope scope = new LibraryImportScope(importingLibrary, errorListener);
+ expect(
+ scope.lookup(AstFactory.identifier3(typeName), importingLibrary), type);
+ errorListener
+ .assertErrorsWithCodes([StaticWarningCode.CONFLICTING_DART_IMPORT]);
+ }
+
+ void test_nonConflictingImports_sameElement() {
+ AnalysisContext context = AnalysisContextFactory.contextWithCore();
+ String typeNameA = "A";
+ String typeNameB = "B";
+ ClassElement typeA = ElementFactory.classElement2(typeNameA);
+ ClassElement typeB = ElementFactory.classElement2(typeNameB);
+ LibraryElement importedLibrary = createTestLibrary(context, "imported");
+ (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[typeA, typeB];
+ ImportElementImpl import1 = ElementFactory.importFor(importedLibrary, null);
+ ImportElementImpl import2 = ElementFactory.importFor(importedLibrary, null);
+ LibraryElementImpl importingLibrary =
+ createTestLibrary(context, "importing");
+ importingLibrary.imports = <ImportElement>[import1, import2];
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ Scope scope = new LibraryImportScope(importingLibrary, errorListener);
+ expect(scope.lookup(AstFactory.identifier3(typeNameA), importingLibrary),
+ typeA);
+ errorListener.assertNoErrors();
+ expect(scope.lookup(AstFactory.identifier3(typeNameB), importingLibrary),
+ typeB);
+ errorListener.assertNoErrors();
+ }
+
+ void test_prefixedAndNonPrefixed() {
+ AnalysisContext context = AnalysisContextFactory.contextWithCore();
+ String typeName = "C";
+ String prefixName = "p";
+ ClassElement prefixedType = ElementFactory.classElement2(typeName);
+ ClassElement nonPrefixedType = ElementFactory.classElement2(typeName);
+ LibraryElement prefixedLibrary =
+ createTestLibrary(context, "import.prefixed");
+ (prefixedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[prefixedType];
+ ImportElementImpl prefixedImport = ElementFactory.importFor(
+ prefixedLibrary, ElementFactory.prefix(prefixName));
+ LibraryElement nonPrefixedLibrary =
+ createTestLibrary(context, "import.nonPrefixed");
+ (nonPrefixedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[nonPrefixedType];
+ ImportElementImpl nonPrefixedImport =
+ ElementFactory.importFor(nonPrefixedLibrary, null);
+ LibraryElementImpl importingLibrary =
+ createTestLibrary(context, "importing");
+ importingLibrary.imports = <ImportElement>[
+ prefixedImport,
+ nonPrefixedImport
+ ];
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ Scope scope = new LibraryImportScope(importingLibrary, errorListener);
+ Element prefixedElement = scope.lookup(
+ AstFactory.identifier5(prefixName, typeName), importingLibrary);
+ errorListener.assertNoErrors();
+ expect(prefixedElement, same(prefixedType));
+ Element nonPrefixedElement =
+ scope.lookup(AstFactory.identifier3(typeName), importingLibrary);
+ errorListener.assertNoErrors();
+ expect(nonPrefixedElement, same(nonPrefixedType));
+ }
+}
+
+@reflectiveTest
+class LibraryResolver2Test extends ResolverTestCase {
+ LibraryResolver2 _resolver;
+
+ Source _coreLibrarySource;
+
+ Source _asyncLibrarySource;
+
+ @override
+ void setUp() {
+ super.setUp();
+ _resolver = new LibraryResolver2(analysisContext2);
+ _coreLibrarySource =
+ analysisContext2.sourceFactory.forUri(DartSdk.DART_CORE);
+ _asyncLibrarySource =
+ analysisContext2.sourceFactory.forUri(DartSdk.DART_ASYNC);
+ }
+
+ void test_imports_relative() {
+ Source sourceA = addSource(r'''
+library libA;
+import 'libB.dart';
+class A {}''');
+ Source sourceB = addNamedSource(
+ "/libB.dart",
+ r'''
+library libB;
+import 'test.dart
+class B {}''');
+ List<ResolvableLibrary> cycle = new List<ResolvableLibrary>();
+ ResolvableLibrary coreLib = _createResolvableLibrary(_coreLibrarySource);
+ coreLib.libraryElement = analysisContext2
+ .computeLibraryElement(_coreLibrarySource) as LibraryElementImpl;
+ ResolvableLibrary asyncLib = _createResolvableLibrary(_asyncLibrarySource);
+ asyncLib.libraryElement = analysisContext2
+ .computeLibraryElement(_asyncLibrarySource) as LibraryElementImpl;
+ ResolvableLibrary libA = _createResolvableLibrary(sourceA);
+ ResolvableLibrary libB = _createResolvableLibrary(sourceB);
+ libA.importedLibraries = <ResolvableLibrary>[coreLib, asyncLib, libB];
+ libB.importedLibraries = <ResolvableLibrary>[coreLib, asyncLib, libA];
+ cycle.add(libA);
+ cycle.add(libB);
+ LibraryElement library = _resolver.resolveLibrary(sourceA, cycle);
+ List<LibraryElement> importedLibraries = library.importedLibraries;
+ assertNamedElements(importedLibraries, ["dart.core", "libB"]);
+ }
+
+ ResolvableLibrary _createResolvableLibrary(Source source) {
+ CompilationUnit unit = analysisContext2.parseCompilationUnit(source);
+ ResolvableLibrary resolvableLibrary = new ResolvableLibrary(source);
+ resolvableLibrary.resolvableCompilationUnits = <ResolvableCompilationUnit>[
+ new ResolvableCompilationUnit(source, unit)
+ ];
+ return resolvableLibrary;
+ }
+}
+
+@reflectiveTest
+class LibraryResolverTest extends ResolverTestCase {
+ LibraryResolver _resolver;
+
+ @override
+ void setUp() {
+ super.setUp();
+ _resolver = new LibraryResolver(analysisContext2);
+ }
+
+ void test_imports_dart_html() {
+ Source source = addSource(r'''
+library libA;
+import 'dart:html';
+class A {}''');
+ LibraryElement library = _resolver.resolveLibrary(source, true);
+ List<LibraryElement> importedLibraries = library.importedLibraries;
+ assertNamedElements(importedLibraries, ["dart.core", "dart.dom.html"]);
+ }
+
+ void test_imports_none() {
+ Source source = addSource(r'''
+library libA;
+class A {}''');
+ LibraryElement library = _resolver.resolveLibrary(source, true);
+ List<LibraryElement> importedLibraries = library.importedLibraries;
+ assertNamedElements(importedLibraries, ["dart.core"]);
+ }
+
+ void test_imports_relative() {
+ addNamedSource("/libB.dart", "library libB;");
+ Source source = addSource(r'''
+library libA;
+import 'libB.dart';
+class A {}''');
+ LibraryElement library = _resolver.resolveLibrary(source, true);
+ List<LibraryElement> importedLibraries = library.importedLibraries;
+ assertNamedElements(importedLibraries, ["dart.core", "libB"]);
+ }
+}
+
+@reflectiveTest
+class LibraryScopeTest extends ResolverTestCase {
+ void test_creation_empty() {
+ LibraryElement definingLibrary = createDefaultTestLibrary();
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ new LibraryScope(definingLibrary, errorListener);
+ }
+
+ void test_creation_nonEmpty() {
+ AnalysisContext context = AnalysisContextFactory.contextWithCore();
+ String importedTypeName = "A";
+ ClassElement importedType =
+ new ClassElementImpl.forNode(AstFactory.identifier3(importedTypeName));
+ LibraryElement importedLibrary = createTestLibrary(context, "imported");
+ (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
+ .types = <ClassElement>[importedType];
+ LibraryElementImpl definingLibrary =
+ createTestLibrary(context, "importing");
+ ImportElementImpl importElement = new ImportElementImpl(0);
+ importElement.importedLibrary = importedLibrary;
+ definingLibrary.imports = <ImportElement>[importElement];
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ Scope scope = new LibraryScope(definingLibrary, errorListener);
+ expect(
+ scope.lookup(AstFactory.identifier3(importedTypeName), definingLibrary),
+ importedType);
+ }
+
+ void test_getErrorListener() {
+ LibraryElement definingLibrary = createDefaultTestLibrary();
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ LibraryScope scope = new LibraryScope(definingLibrary, errorListener);
+ expect(scope.errorListener, errorListener);
+ }
+}
+
+@reflectiveTest
+class LibraryTest extends EngineTestCase {
+ /**
+ * The error listener to which all errors will be reported.
+ */
+ GatheringErrorListener _errorListener;
+
+ /**
+ * The analysis context to pass in to all libraries created by the tests.
+ */
+ InternalAnalysisContext _analysisContext;
+
+ /**
+ * The library used by the tests.
+ */
+ Library _library;
+
+ @override
+ void setUp() {
+ _analysisContext = AnalysisContextFactory.contextWithCore();
+ _errorListener = new GatheringErrorListener();
+ _library = _createLibrary("/lib.dart");
+ }
+
+ @override
+ void tearDown() {
+ _errorListener = null;
+ _analysisContext = null;
+ _library = null;
+ super.tearDown();
+ }
+
+ void test_getExplicitlyImportsCore() {
+ expect(_library.explicitlyImportsCore, isFalse);
+ _errorListener.assertNoErrors();
+ }
+
+ void test_getExports() {
+ expect(_library.exports, hasLength(0));
+ _errorListener.assertNoErrors();
+ }
+
+ void test_getImports() {
+ expect(_library.imports, hasLength(0));
+ _errorListener.assertNoErrors();
+ }
+
+ void test_getImportsAndExports() {
+ _library.importedLibraries = <Library>[_createLibrary("/imported.dart")];
+ _library.exportedLibraries = <Library>[_createLibrary("/exported.dart")];
+ expect(_library.importsAndExports, hasLength(2));
+ _errorListener.assertNoErrors();
+ }
+
+ void test_getLibraryScope() {
+ LibraryElementImpl element = new LibraryElementImpl.forNode(
+ _analysisContext, AstFactory.libraryIdentifier2(["lib"]));
+ element.definingCompilationUnit =
+ new CompilationUnitElementImpl("lib.dart");
+ _library.libraryElement = element;
+ expect(_library.libraryScope, isNotNull);
+ _errorListener.assertNoErrors();
+ }
+
+ void test_getLibrarySource() {
+ expect(_library.librarySource, isNotNull);
+ }
+
+ void test_setExplicitlyImportsCore() {
+ _library.explicitlyImportsCore = true;
+ expect(_library.explicitlyImportsCore, isTrue);
+ _errorListener.assertNoErrors();
+ }
+
+ void test_setExportedLibraries() {
+ Library exportLibrary = _createLibrary("/exported.dart");
+ _library.exportedLibraries = <Library>[exportLibrary];
+ List<Library> exports = _library.exports;
+ expect(exports, hasLength(1));
+ expect(exports[0], same(exportLibrary));
+ _errorListener.assertNoErrors();
+ }
+
+ void test_setImportedLibraries() {
+ Library importLibrary = _createLibrary("/imported.dart");
+ _library.importedLibraries = <Library>[importLibrary];
+ List<Library> imports = _library.imports;
+ expect(imports, hasLength(1));
+ expect(imports[0], same(importLibrary));
+ _errorListener.assertNoErrors();
+ }
+
+ void test_setLibraryElement() {
+ LibraryElementImpl element = new LibraryElementImpl.forNode(
+ _analysisContext, AstFactory.libraryIdentifier2(["lib"]));
+ _library.libraryElement = element;
+ expect(_library.libraryElement, same(element));
+ }
+
+ Library _createLibrary(String definingCompilationUnitPath) => new Library(
+ _analysisContext,
+ _errorListener,
+ new FileBasedSource(
+ FileUtilities2.createFile(definingCompilationUnitPath)));
+}
+
+@reflectiveTest
+class MemberMapTest {
+ /**
+ * The null type.
+ */
+ InterfaceType _nullType;
+
+ void setUp() {
+ _nullType = new TestTypeProvider().nullType;
+ }
+
+ void test_MemberMap_copyConstructor() {
+ MethodElement m1 = ElementFactory.methodElement("m1", _nullType);
+ MethodElement m2 = ElementFactory.methodElement("m2", _nullType);
+ MethodElement m3 = ElementFactory.methodElement("m3", _nullType);
+ MemberMap map = new MemberMap();
+ map.put(m1.name, m1);
+ map.put(m2.name, m2);
+ map.put(m3.name, m3);
+ MemberMap copy = new MemberMap.from(map);
+ expect(copy.size, map.size);
+ expect(copy.get(m1.name), m1);
+ expect(copy.get(m2.name), m2);
+ expect(copy.get(m3.name), m3);
+ }
+
+ void test_MemberMap_override() {
+ MethodElement m1 = ElementFactory.methodElement("m", _nullType);
+ MethodElement m2 = ElementFactory.methodElement("m", _nullType);
+ MemberMap map = new MemberMap();
+ map.put(m1.name, m1);
+ map.put(m2.name, m2);
+ expect(map.size, 1);
+ expect(map.get("m"), m2);
+ }
+
+ void test_MemberMap_put() {
+ MethodElement m1 = ElementFactory.methodElement("m1", _nullType);
+ MemberMap map = new MemberMap();
+ expect(map.size, 0);
+ map.put(m1.name, m1);
+ expect(map.size, 1);
+ expect(map.get("m1"), m1);
+ }
+}
+
+/**
+ * An analysis context that has a fake SDK that is much smaller and faster for
+ * testing purposes.
+ */
+class NewAnalysisContextForTests extends newContext.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.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;
+ }
+}
+
+@reflectiveTest
+class NonHintCodeTest extends ResolverTestCase {
+ void test_deadCode_deadBlock_conditionalElse_debugConst() {
+ Source source = addSource(r'''
+const bool DEBUG = true;
+f() {
+ DEBUG ? 1 : 2;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_deadCode_deadBlock_conditionalIf_debugConst() {
+ Source source = addSource(r'''
+const bool DEBUG = false;
+f() {
+ DEBUG ? 1 : 2;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_deadCode_deadBlock_else() {
+ Source source = addSource(r'''
+const bool DEBUG = true;
+f() {
+ if(DEBUG) {} else {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_deadCode_deadBlock_if_debugConst_prefixedIdentifier() {
+ Source source = addSource(r'''
+class A {
+ static const bool DEBUG = false;
+}
+f() {
+ if(A.DEBUG) {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_deadCode_deadBlock_if_debugConst_prefixedIdentifier2() {
+ Source source = addSource(r'''
+library L;
+import 'lib2.dart';
+f() {
+ if(A.DEBUG) {}
+}''');
+ addNamedSource(
+ "/lib2.dart",
+ r'''
+library lib2;
+class A {
+ static const bool DEBUG = false;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_deadCode_deadBlock_if_debugConst_propertyAccessor() {
+ Source source = addSource(r'''
+library L;
+import 'lib2.dart' as LIB;
+f() {
+ if(LIB.A.DEBUG) {}
+}''');
+ addNamedSource(
+ "/lib2.dart",
+ r'''
+library lib2;
+class A {
+ static const bool DEBUG = false;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_deadCode_deadBlock_if_debugConst_simpleIdentifier() {
+ Source source = addSource(r'''
+const bool DEBUG = false;
+f() {
+ if(DEBUG) {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_deadCode_deadBlock_while_debugConst() {
+ Source source = addSource(r'''
+const bool DEBUG = false;
+f() {
+ while(DEBUG) {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_deadCode_deadCatch_onCatchSubtype() {
+ Source source = addSource(r'''
+class A {}
+class B extends A {}
+f() {
+ try {} on B catch (e) {} on A catch (e) {} catch (e) {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_deadCode_deadOperandLHS_and_debugConst() {
+ Source source = addSource(r'''
+const bool DEBUG = false;
+f() {
+ bool b = DEBUG && false;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_deadCode_deadOperandLHS_or_debugConst() {
+ Source source = addSource(r'''
+const bool DEBUG = true;
+f() {
+ bool b = DEBUG || true;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_divisionOptimization() {
+ Source source = addSource(r'''
+f(int x, int y) {
+ var v = x / y.toInt();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_divisionOptimization_supressIfDivisionNotDefinedInCore() {
+ Source source = addSource(r'''
+f(x, y) {
+ var v = (x / y).toInt();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_divisionOptimization_supressIfDivisionOverridden() {
+ Source source = addSource(r'''
+class A {
+ num operator /(x) { return x; }
+}
+f(A x, A y) {
+ var v = (x / y).toInt();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_duplicateImport_as() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+import 'lib1.dart' as one;
+A a;
+one.A a2;''');
+ addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+class A {}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_duplicateImport_hide() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+import 'lib1.dart' hide A;
+A a;
+B b;''');
+ addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+class A {}
+class B {}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_duplicateImport_show() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+import 'lib1.dart' show A;
+A a;
+B b;''');
+ addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+class A {}
+class B {}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_importDeferredLibraryWithLoadFunction() {
+ resolveWithErrors(<String>[
+ r'''
+library lib1;
+f() {}''',
+ r'''
+library root;
+import 'lib1.dart' deferred as lib1;
+main() { lib1.f(); }'''
+ ], ErrorCode.EMPTY_LIST);
+ }
+
+ void test_issue20904BuggyTypePromotionAtIfJoin_1() {
+ // https://code.google.com/p/dart/issues/detail?id=20904
+ Source source = addSource(r'''
+f(var message, var dynamic_) {
+ if (message is Function) {
+ message = dynamic_;
+ }
+ int s = message;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_issue20904BuggyTypePromotionAtIfJoin_3() {
+ // https://code.google.com/p/dart/issues/detail?id=20904
+ Source source = addSource(r'''
+f(var message) {
+ var dynamic_;
+ if (message is Function) {
+ message = dynamic_;
+ } else {
+ return;
+ }
+ int s = message;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_issue20904BuggyTypePromotionAtIfJoin_4() {
+ // https://code.google.com/p/dart/issues/detail?id=20904
+ Source source = addSource(r'''
+f(var message) {
+ if (message is Function) {
+ message = '';
+ } else {
+ return;
+ }
+ String s = message;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_missingReturn_emptyFunctionBody() {
+ Source source = addSource(r'''
+abstract class A {
+ int m();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_missingReturn_expressionFunctionBody() {
+ Source source = addSource("int f() => 0;");
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_missingReturn_noReturnType() {
+ Source source = addSource("f() {}");
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_missingReturn_voidReturnType() {
+ Source source = addSource("void f() {}");
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_overrideEqualsButNotHashCode() {
+ Source source = addSource(r'''
+class A {
+ bool operator ==(x) { return x; }
+ get hashCode => 0;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_overrideOnNonOverridingGetter_inInterface() {
+ Source source = addSource(r'''
+library dart.core;
+const override = null;
+class A {
+ int get m => 0;
+}
+class B implements A {
+ @override
+ int get m => 1;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_overrideOnNonOverridingGetter_inSuperclass() {
+ Source source = addSource(r'''
+library dart.core;
+const override = null;
+class A {
+ int get m => 0;
+}
+class B extends A {
+ @override
+ int get m => 1;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_overrideOnNonOverridingMethod_inInterface() {
+ Source source = addSource(r'''
+library dart.core;
+const override = null;
+class A {
+ int m() => 0;
+}
+class B implements A {
+ @override
+ int m() => 1;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_overrideOnNonOverridingMethod_inSuperclass() {
+ Source source = addSource(r'''
+library dart.core;
+const override = null;
+class A {
+ int m() => 0;
+}
+class B extends A {
+ @override
+ int m() => 1;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_overrideOnNonOverridingSetter_inInterface() {
+ Source source = addSource(r'''
+library dart.core;
+const override = null;
+class A {
+ set m(int x) {}
+}
+class B implements A {
+ @override
+ set m(int x) {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_overrideOnNonOverridingSetter_inSuperclass() {
+ Source source = addSource(r'''
+library dart.core;
+const override = null;
+class A {
+ set m(int x) {}
+}
+class B extends A {
+ @override
+ set m(int x) {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_propagatedFieldType() {
+ Source source = addSource(r'''
+class A { }
+class X<T> {
+ final x = new List<T>();
+}
+class Z {
+ final X<A> y = new X<A>();
+ foo() {
+ y.x.add(new A());
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_proxy_annotation_prefixed() {
+ Source source = addSource(r'''
+library L;
+@proxy
+class A {}
+f(var a) {
+ a = new A();
+ a.m();
+ var x = a.g;
+ a.s = 1;
+ var y = a + a;
+ a++;
+ ++a;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_proxy_annotation_prefixed2() {
+ Source source = addSource(r'''
+library L;
+@proxy
+class A {}
+class B {
+ f(var a) {
+ a = new A();
+ a.m();
+ var x = a.g;
+ a.s = 1;
+ var y = a + a;
+ a++;
+ ++a;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_proxy_annotation_prefixed3() {
+ Source source = addSource(r'''
+library L;
+class B {
+ f(var a) {
+ a = new A();
+ a.m();
+ var x = a.g;
+ a.s = 1;
+ var y = a + a;
+ a++;
+ ++a;
+ }
+}
+@proxy
+class A {}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_undefinedGetter_inSubtype() {
+ Source source = addSource(r'''
+class A {}
+class B extends A {
+ get b => 0;
+}
+f(var a) {
+ if(a is A) {
+ return a.b;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_undefinedMethod_assignmentExpression_inSubtype() {
+ Source source = addSource(r'''
+class A {}
+class B extends A {
+ operator +(B b) {return new B();}
+}
+f(var a, var a2) {
+ a = new A();
+ a2 = new A();
+ a += a2;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_undefinedMethod_dynamic() {
+ Source source = addSource(r'''
+class D<T extends dynamic> {
+ fieldAccess(T t) => t.abc;
+ methodAccess(T t) => t.xyz(1, 2, 'three');
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_undefinedMethod_inSubtype() {
+ Source source = addSource(r'''
+class A {}
+class B extends A {
+ b() {}
+}
+f() {
+ var a = new A();
+ a.b();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_undefinedMethod_unionType_all() {
+ Source source = addSource(r'''
+class A {
+ int m(int x) => 0;
+}
+class B {
+ String m() => '0';
+}
+f(A a, B b) {
+ var ab;
+ if (0 < 1) {
+ ab = a;
+ } else {
+ ab = b;
+ }
+ ab.m();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_undefinedMethod_unionType_some() {
+ Source source = addSource(r'''
+class A {
+ int m(int x) => 0;
+}
+class B {}
+f(A a, B b) {
+ var ab;
+ if (0 < 1) {
+ ab = a;
+ } else {
+ ab = b;
+ }
+ ab.m(0);
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_undefinedOperator_binaryExpression_inSubtype() {
+ Source source = addSource(r'''
+class A {}
+class B extends A {
+ operator +(B b) {}
+}
+f(var a) {
+ if(a is A) {
+ a + 1;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_undefinedOperator_indexBoth_inSubtype() {
+ Source source = addSource(r'''
+class A {}
+class B extends A {
+ operator [](int index) {}
+}
+f(var a) {
+ if(a is A) {
+ a[0]++;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_undefinedOperator_indexGetter_inSubtype() {
+ Source source = addSource(r'''
+class A {}
+class B extends A {
+ operator [](int index) {}
+}
+f(var a) {
+ if(a is A) {
+ a[0];
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_undefinedOperator_indexSetter_inSubtype() {
+ Source source = addSource(r'''
+class A {}
+class B extends A {
+ operator []=(i, v) {}
+}
+f(var a) {
+ if(a is A) {
+ a[0] = 1;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_undefinedOperator_postfixExpression() {
+ Source source = addSource(r'''
+class A {}
+class B extends A {
+ operator +(B b) {return new B();}
+}
+f(var a) {
+ if(a is A) {
+ a++;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_undefinedOperator_prefixExpression() {
+ Source source = addSource(r'''
+class A {}
+class B extends A {
+ operator +(B b) {return new B();}
+}
+f(var a) {
+ if(a is A) {
+ ++a;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_undefinedSetter_inSubtype() {
+ Source source = addSource(r'''
+class A {}
+class B extends A {
+ set b(x) {}
+}
+f(var a) {
+ if(a is A) {
+ a.b = 0;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_unnecessaryCast_13855_parameter_A() {
+ // dartbug.com/13855, dartbug.com/13732
+ Source source = addSource(r'''
+class A{
+ a() {}
+}
+class B<E> {
+ E e;
+ m() {
+ (e as A).a();
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unnecessaryCast_conditionalExpression() {
+ Source source = addSource(r'''
+abstract class I {}
+class A implements I {}
+class B implements I {}
+I m(A a, B b) {
+ return a == null ? b as I : a as I;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unnecessaryCast_dynamic_type() {
+ Source source = addSource(r'''
+m(v) {
+ var b = v as Object;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unnecessaryCast_generics() {
+ // dartbug.com/18953
+ Source source = addSource(r'''
+import 'dart:async';
+Future<int> f() => new Future.value(0);
+void g(bool c) {
+ (c ? f(): new Future.value(0) as Future<int>).then((int value) {});
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unnecessaryCast_type_dynamic() {
+ Source source = addSource(r'''
+m(v) {
+ var b = Object as dynamic;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedImport_annotationOnDirective() {
+ Source source = addSource(r'''
+library L;
+@A()
+import 'lib1.dart';''');
+ Source source2 = addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+class A {
+ const A() {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ verify([source, source2]);
+ }
+
+ void test_unusedImport_as_equalPrefixes() {
+ // 18818
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart' as one;
+import 'lib2.dart' as one;
+one.A a;
+one.B b;''');
+ Source source2 = addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+class A {}''');
+ Source source3 = addNamedSource(
+ "/lib2.dart",
+ r'''
+library lib2;
+class B {}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source);
+ assertNoErrors(source2);
+ assertNoErrors(source3);
+ verify([source, source2, source3]);
+ }
+
+ void test_unusedImport_core_library() {
+ Source source = addSource(r'''
+library L;
+import 'dart:core';''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedImport_export() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+Two two;''');
+ addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+export 'lib2.dart';
+class One {}''');
+ addNamedSource(
+ "/lib2.dart",
+ r'''
+library lib2;
+class Two {}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedImport_export2() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+Three three;''');
+ addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+export 'lib2.dart';
+class One {}''');
+ addNamedSource(
+ "/lib2.dart",
+ r'''
+library lib2;
+export 'lib3.dart';
+class Two {}''');
+ addNamedSource(
+ "/lib3.dart",
+ r'''
+library lib3;
+class Three {}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedImport_export_infiniteLoop() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart';
+Two two;''');
+ addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+export 'lib2.dart';
+class One {}''');
+ addNamedSource(
+ "/lib2.dart",
+ r'''
+library lib2;
+export 'lib3.dart';
+class Two {}''');
+ addNamedSource(
+ "/lib3.dart",
+ r'''
+library lib3;
+export 'lib2.dart';
+class Three {}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedImport_metadata() {
+ Source source = addSource(r'''
+library L;
+@A(x)
+import 'lib1.dart';
+class A {
+ final int value;
+ const A(this.value);
+}''');
+ addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+const x = 0;''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_unusedImport_prefix_topLevelFunction() {
+ Source source = addSource(r'''
+library L;
+import 'lib1.dart' hide topLevelFunction;
+import 'lib1.dart' as one show topLevelFunction;
+class A {
+ static void x() {
+ One o;
+ one.topLevelFunction();
+ }
+}''');
+ addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+class One {}
+topLevelFunction() {}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_implicitReturnValue() {
+ Source source = addSource(r'''
+f() {}
+class A {
+ n() {
+ var a = f();
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_useOfVoidResult_nonVoidReturnValue() {
+ Source source = addSource(r'''
+int f() => 1;
+g() {
+ var a = f();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+}
+
+class PubSuggestionCodeTest extends ResolverTestCase {
+ void test_import_package() {
+ Source source = addSource("import 'package:somepackage/other.dart';");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [CompileTimeErrorCode.URI_DOES_NOT_EXIST]);
+ }
+
+ void test_import_packageWithDotDot() {
+ Source source = addSource("import 'package:somepackage/../other.dart';");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [
+ CompileTimeErrorCode.URI_DOES_NOT_EXIST,
+ HintCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT
+ ]);
+ }
+
+ void test_import_packageWithLeadingDotDot() {
+ Source source = addSource("import 'package:../other.dart';");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [
+ CompileTimeErrorCode.URI_DOES_NOT_EXIST,
+ HintCode.PACKAGE_IMPORT_CONTAINS_DOT_DOT
+ ]);
+ }
+
+ void test_import_referenceIntoLibDirectory() {
+ cacheSource("/myproj/pubspec.yaml", "");
+ cacheSource("/myproj/lib/other.dart", "");
+ Source source =
+ addNamedSource("/myproj/web/test.dart", "import '../lib/other.dart';");
+ computeLibrarySourceErrors(source);
+ assertErrors(
+ source, [HintCode.FILE_IMPORT_OUTSIDE_LIB_REFERENCES_FILE_INSIDE]);
+ }
+
+ void test_import_referenceIntoLibDirectory_no_pubspec() {
+ cacheSource("/myproj/lib/other.dart", "");
+ Source source =
+ addNamedSource("/myproj/web/test.dart", "import '../lib/other.dart';");
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_import_referenceOutOfLibDirectory() {
+ cacheSource("/myproj/pubspec.yaml", "");
+ cacheSource("/myproj/web/other.dart", "");
+ Source source =
+ addNamedSource("/myproj/lib/test.dart", "import '../web/other.dart';");
+ computeLibrarySourceErrors(source);
+ assertErrors(
+ source, [HintCode.FILE_IMPORT_INSIDE_LIB_REFERENCES_FILE_OUTSIDE]);
+ }
+
+ void test_import_referenceOutOfLibDirectory_no_pubspec() {
+ cacheSource("/myproj/web/other.dart", "");
+ Source source =
+ addNamedSource("/myproj/lib/test.dart", "import '../web/other.dart';");
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_import_valid_inside_lib1() {
+ cacheSource("/myproj/pubspec.yaml", "");
+ cacheSource("/myproj/lib/other.dart", "");
+ Source source =
+ addNamedSource("/myproj/lib/test.dart", "import 'other.dart';");
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_import_valid_inside_lib2() {
+ cacheSource("/myproj/pubspec.yaml", "");
+ cacheSource("/myproj/lib/bar/other.dart", "");
+ Source source = addNamedSource(
+ "/myproj/lib/foo/test.dart", "import '../bar/other.dart';");
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_import_valid_outside_lib() {
+ cacheSource("/myproj/pubspec.yaml", "");
+ cacheSource("/myproj/web/other.dart", "");
+ Source source =
+ addNamedSource("/myproj/lib2/test.dart", "import '../web/other.dart';");
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+}
+
+/**
+ * An AST visitor used to verify that all of the nodes in an AST structure that
+ * should have been resolved were resolved.
+ */
+class ResolutionVerifier extends RecursiveAstVisitor<Object> {
+ /**
+ * A set containing nodes that are known to not be resolvable and should
+ * therefore not cause the test to fail.
+ */
+ final Set<AstNode> _knownExceptions;
+
+ /**
+ * A list containing all of the AST nodes that were not resolved.
+ */
+ List<AstNode> _unresolvedNodes = new List<AstNode>();
+
+ /**
+ * A list containing all of the AST nodes that were resolved to an element of
+ * the wrong type.
+ */
+ List<AstNode> _wrongTypedNodes = new List<AstNode>();
+
+ /**
+ * Initialize a newly created verifier to verify that all of the identifiers
+ * in the visited AST structures that are expected to have been resolved have
+ * an element associated with them. Nodes in the set of [_knownExceptions] are
+ * not expected to have been resolved, even if they normally would have been
+ * expected to have been resolved.
+ */
+ ResolutionVerifier([this._knownExceptions]);
+
+ /**
+ * Assert that all of the visited identifiers were resolved.
+ */
+ void assertResolved() {
+ if (!_unresolvedNodes.isEmpty || !_wrongTypedNodes.isEmpty) {
+ StringBuffer buffer = new StringBuffer();
+ if (!_unresolvedNodes.isEmpty) {
+ buffer.write("Failed to resolve ");
+ buffer.write(_unresolvedNodes.length);
+ buffer.writeln(" nodes:");
+ _printNodes(buffer, _unresolvedNodes);
+ }
+ if (!_wrongTypedNodes.isEmpty) {
+ buffer.write("Resolved ");
+ buffer.write(_wrongTypedNodes.length);
+ buffer.writeln(" to the wrong type of element:");
+ _printNodes(buffer, _wrongTypedNodes);
+ }
+ fail(buffer.toString());
+ }
+ }
+
+ @override
+ Object visitAnnotation(Annotation node) {
+ node.visitChildren(this);
+ ElementAnnotation elementAnnotation = node.elementAnnotation;
+ if (elementAnnotation == null) {
+ if (_knownExceptions == null || !_knownExceptions.contains(node)) {
+ _unresolvedNodes.add(node);
+ }
+ } else if (elementAnnotation is! ElementAnnotation) {
+ _wrongTypedNodes.add(node);
+ }
+ return null;
+ }
+
+ @override
+ Object visitBinaryExpression(BinaryExpression node) {
+ node.visitChildren(this);
+ if (!node.operator.isUserDefinableOperator) {
+ return null;
+ }
+ DartType operandType = node.leftOperand.staticType;
+ if (operandType == null || operandType.isDynamic) {
+ return null;
+ }
+ return _checkResolved(
+ node, node.staticElement, (node) => node is MethodElement);
+ }
+
+ @override
+ Object visitCommentReference(CommentReference node) => null;
+
+ @override
+ Object visitCompilationUnit(CompilationUnit node) {
+ node.visitChildren(this);
+ return _checkResolved(
+ node, node.element, (node) => node is CompilationUnitElement);
+ }
+
+ @override
+ Object visitExportDirective(ExportDirective node) =>
+ _checkResolved(node, node.element, (node) => node is ExportElement);
+
+ @override
+ Object visitFunctionDeclaration(FunctionDeclaration node) {
+ node.visitChildren(this);
+ if (node.element is LibraryElement) {
+ _wrongTypedNodes.add(node);
+ }
+ return null;
+ }
+
+ @override
+ Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
+ node.visitChildren(this);
+ // TODO(brianwilkerson) If we start resolving function expressions, then
+ // conditionally check to see whether the node was resolved correctly.
+ return null;
+ //checkResolved(node, node.getElement(), FunctionElement.class);
+ }
+
+ @override
+ Object visitImportDirective(ImportDirective node) {
+ // Not sure how to test the combinators given that it isn't an error if the
+ // names are not defined.
+ _checkResolved(node, node.element, (node) => node is ImportElement);
+ SimpleIdentifier prefix = node.prefix;
+ if (prefix == null) {
+ return null;
+ }
+ return _checkResolved(
+ prefix, prefix.staticElement, (node) => node is PrefixElement);
+ }
+
+ @override
+ Object visitIndexExpression(IndexExpression node) {
+ node.visitChildren(this);
+ DartType targetType = node.realTarget.staticType;
+ if (targetType == null || targetType.isDynamic) {
+ return null;
+ }
+ return _checkResolved(
+ node, node.staticElement, (node) => node is MethodElement);
+ }
+
+ @override
+ Object visitLibraryDirective(LibraryDirective node) =>
+ _checkResolved(node, node.element, (node) => node is LibraryElement);
+
+ @override
+ Object visitNamedExpression(NamedExpression node) =>
+ node.expression.accept(this);
+
+ @override
+ Object visitPartDirective(PartDirective node) => _checkResolved(
+ node, node.element, (node) => node is CompilationUnitElement);
+
+ @override
+ Object visitPartOfDirective(PartOfDirective node) =>
+ _checkResolved(node, node.element, (node) => node is LibraryElement);
+
+ @override
+ Object visitPostfixExpression(PostfixExpression node) {
+ node.visitChildren(this);
+ if (!node.operator.isUserDefinableOperator) {
+ return null;
+ }
+ DartType operandType = node.operand.staticType;
+ if (operandType == null || operandType.isDynamic) {
+ return null;
+ }
+ return _checkResolved(
+ node, node.staticElement, (node) => node is MethodElement);
+ }
+
+ @override
+ Object visitPrefixedIdentifier(PrefixedIdentifier node) {
+ SimpleIdentifier prefix = node.prefix;
+ prefix.accept(this);
+ DartType prefixType = prefix.staticType;
+ if (prefixType == null || prefixType.isDynamic) {
+ return null;
+ }
+ return _checkResolved(node, node.staticElement, null);
+ }
+
+ @override
+ Object visitPrefixExpression(PrefixExpression node) {
+ node.visitChildren(this);
+ if (!node.operator.isUserDefinableOperator) {
+ return null;
+ }
+ DartType operandType = node.operand.staticType;
+ if (operandType == null || operandType.isDynamic) {
+ return null;
+ }
+ return _checkResolved(
+ node, node.staticElement, (node) => node is MethodElement);
+ }
+
+ @override
+ Object visitPropertyAccess(PropertyAccess node) {
+ Expression target = node.realTarget;
+ target.accept(this);
+ DartType targetType = target.staticType;
+ if (targetType == null || targetType.isDynamic) {
+ return null;
+ }
+ return node.propertyName.accept(this);
+ }
+
+ @override
+ Object visitSimpleIdentifier(SimpleIdentifier node) {
+ if (node.name == "void") {
+ return null;
+ }
+ AstNode parent = node.parent;
+ if (parent is MethodInvocation) {
+ MethodInvocation invocation = parent;
+ if (identical(invocation.methodName, node)) {
+ Expression target = invocation.realTarget;
+ DartType targetType = target == null ? null : target.staticType;
+ if (targetType == null || targetType.isDynamic) {
+ return null;
+ }
+ }
+ }
+ return _checkResolved(node, node.staticElement, null);
+ }
+
+ Object _checkResolved(
+ AstNode node, Element element, Predicate<Element> predicate) {
+ if (element == null) {
+ if (_knownExceptions == null || !_knownExceptions.contains(node)) {
+ _unresolvedNodes.add(node);
+ }
+ } else if (predicate != null) {
+ if (!predicate(element)) {
+ _wrongTypedNodes.add(node);
+ }
+ }
+ return null;
+ }
+
+ String _getFileName(AstNode node) {
+ // TODO (jwren) there are two copies of this method, one here and one in
+ // StaticTypeVerifier, they should be resolved into a single method
+ if (node != null) {
+ AstNode root = node.root;
+ if (root is CompilationUnit) {
+ CompilationUnit rootCU = root;
+ if (rootCU.element != null) {
+ return rootCU.element.source.fullName;
+ } else {
+ return "<unknown file- CompilationUnit.getElement() returned null>";
+ }
+ } else {
+ return "<unknown file- CompilationUnit.getRoot() is not a CompilationUnit>";
+ }
+ }
+ return "<unknown file- ASTNode is null>";
+ }
+
+ void _printNodes(StringBuffer buffer, List<AstNode> nodes) {
+ for (AstNode identifier in nodes) {
+ buffer.write(" ");
+ buffer.write(identifier.toString());
+ buffer.write(" (");
+ buffer.write(_getFileName(identifier));
+ buffer.write(" : ");
+ buffer.write(identifier.offset);
+ buffer.writeln(")");
+ }
+ }
+}
+
+class ResolverTestCase extends EngineTestCase {
+ /**
+ * The analysis context used to parse the compilation units being resolved.
+ */
+ InternalAnalysisContext analysisContext2;
+
+ /**
+ * Specifies if [assertErrors] should check for [HintCode.UNUSED_ELEMENT] and
+ * [HintCode.UNUSED_FIELD].
+ */
+ bool enableUnusedElement = false;
+
+ /**
+ * Specifies if [assertErrors] should check for [HintCode.UNUSED_LOCAL_VARIABLE].
+ */
+ bool enableUnusedLocalVariable = false;
+
+ AnalysisContext get analysisContext => analysisContext2;
+
+ /**
+ * Return a type provider that can be used to test the results of resolution.
+ *
+ * @return a type provider
+ * @throws AnalysisException if dart:core cannot be resolved
+ */
+ TypeProvider get typeProvider => analysisContext2.typeProvider;
+
+ /**
+ * Return a type system that can be used to test the results of resolution.
+ *
+ * @return a type system
+ */
+ TypeSystem get typeSystem => analysisContext2.typeSystem;
+
+ /**
+ * Add a source file to the content provider. The file path should be absolute.
+ *
+ * @param filePath the path of the file being added
+ * @param contents the contents to be returned by the content provider for the specified file
+ * @return the source object representing the added file
+ */
+ Source addNamedSource(String filePath, String contents) {
+ Source source = cacheSource(filePath, contents);
+ ChangeSet changeSet = new ChangeSet();
+ changeSet.addedSource(source);
+ analysisContext2.applyChanges(changeSet);
+ return source;
+ }
+
+ /**
+ * Add a source file to the content provider.
+ *
+ * @param contents the contents to be returned by the content provider for the specified file
+ * @return the source object representing the added file
+ */
+ Source addSource(String contents) => addNamedSource("/test.dart", contents);
+
+ /**
+ * Assert that the number of errors reported against the given source matches the number of errors
+ * that are given and that they have the expected error codes. The order in which the errors were
+ * gathered is ignored.
+ *
+ * @param source the source against which the errors should have been reported
+ * @param expectedErrorCodes the error codes of the errors that should have been reported
+ * @throws AnalysisException if the reported errors could not be computed
+ * @throws AssertionFailedError if a different number of errors have been reported than were
+ * expected
+ */
+ void assertErrors(Source source,
+ [List<ErrorCode> expectedErrorCodes = ErrorCode.EMPTY_LIST]) {
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ for (AnalysisError error in analysisContext2.computeErrors(source)) {
+ ErrorCode errorCode = error.errorCode;
+ if (!enableUnusedElement &&
+ (errorCode == HintCode.UNUSED_ELEMENT ||
+ errorCode == HintCode.UNUSED_FIELD)) {
+ continue;
+ }
+ if (!enableUnusedLocalVariable &&
+ (errorCode == HintCode.UNUSED_CATCH_CLAUSE ||
+ errorCode == HintCode.UNUSED_CATCH_STACK ||
+ errorCode == HintCode.UNUSED_LOCAL_VARIABLE)) {
+ continue;
+ }
+ errorListener.onError(error);
+ }
+ errorListener.assertErrorsWithCodes(expectedErrorCodes);
+ }
+
+ /**
+ * Assert that no errors have been reported against the given source.
+ *
+ * @param source the source against which no errors should have been reported
+ * @throws AnalysisException if the reported errors could not be computed
+ * @throws AssertionFailedError if any errors have been reported
+ */
+ void assertNoErrors(Source source) {
+ assertErrors(source);
+ }
+
+ /**
+ * Cache the source file content in the source factory but don't add the source to the analysis
+ * context. The file path should be absolute.
+ *
+ * @param filePath the path of the file being cached
+ * @param contents the contents to be returned by the content provider for the specified file
+ * @return the source object representing the cached file
+ */
+ Source cacheSource(String filePath, String contents) {
+ Source source = new FileBasedSource(FileUtilities2.createFile(filePath));
+ analysisContext2.setContents(source, contents);
+ return source;
+ }
+
+ /**
+ * Change the contents of the given [source] to the given [contents].
+ */
+ void changeSource(Source source, String contents) {
+ analysisContext2.setContents(source, contents);
+ ChangeSet changeSet = new ChangeSet();
+ changeSet.changedSource(source);
+ analysisContext2.applyChanges(changeSet);
+ }
+
+ /**
+ * Computes errors for the given [librarySource].
+ * This assumes that the given [librarySource] and its parts have already
+ * been added to the content provider using the method [addNamedSource].
+ */
+ void computeLibrarySourceErrors(Source librarySource) {
+ analysisContext.computeErrors(librarySource);
+ }
+
+ /**
+ * Create a library element that represents a library named `"test"` containing a single
+ * empty compilation unit.
+ *
+ * @return the library element that was created
+ */
+ LibraryElementImpl createDefaultTestLibrary() =>
+ createTestLibrary(AnalysisContextFactory.contextWithCore(), "test");
+
+ /**
+ * Create a library element that represents a library with the given name containing a single
+ * empty compilation unit.
+ *
+ * @param libraryName the name of the library to be created
+ * @return the library element that was created
+ */
+ LibraryElementImpl createTestLibrary(
+ AnalysisContext context, String libraryName,
+ [List<String> typeNames]) {
+ String fileName = "$libraryName.dart";
+ FileBasedSource definingCompilationUnitSource =
+ _createNamedSource(fileName);
+ List<CompilationUnitElement> sourcedCompilationUnits;
+ if (typeNames == null) {
+ sourcedCompilationUnits = CompilationUnitElement.EMPTY_LIST;
+ } else {
+ int count = typeNames.length;
+ sourcedCompilationUnits = new List<CompilationUnitElement>(count);
+ for (int i = 0; i < count; i++) {
+ String typeName = typeNames[i];
+ ClassElementImpl type =
+ new ClassElementImpl.forNode(AstFactory.identifier3(typeName));
+ String fileName = "$typeName.dart";
+ CompilationUnitElementImpl compilationUnit =
+ new CompilationUnitElementImpl(fileName);
+ compilationUnit.source = _createNamedSource(fileName);
+ compilationUnit.librarySource = definingCompilationUnitSource;
+ compilationUnit.types = <ClassElement>[type];
+ sourcedCompilationUnits[i] = compilationUnit;
+ }
+ }
+ CompilationUnitElementImpl compilationUnit =
+ new CompilationUnitElementImpl(fileName);
+ compilationUnit.librarySource =
+ compilationUnit.source = definingCompilationUnitSource;
+ LibraryElementImpl library = new LibraryElementImpl.forNode(
+ context, AstFactory.libraryIdentifier2([libraryName]));
+ library.definingCompilationUnit = compilationUnit;
+ library.parts = sourcedCompilationUnits;
+ return library;
+ }
+
+ Expression findTopLevelConstantExpression(
+ CompilationUnit compilationUnit, String name) =>
+ findTopLevelDeclaration(compilationUnit, name).initializer;
+
+ VariableDeclaration findTopLevelDeclaration(
+ CompilationUnit compilationUnit, String name) {
+ for (CompilationUnitMember member in compilationUnit.declarations) {
+ if (member is TopLevelVariableDeclaration) {
+ for (VariableDeclaration variable in member.variables.variables) {
+ if (variable.name.name == name) {
+ return variable;
+ }
+ }
+ }
+ }
+ return null;
+ // Not found
+ }
+
+ /**
+ * In the rare cases we want to group several tests into single "test_" method, so need a way to
+ * reset test instance to reuse it.
+ */
+ void reset() {
+ analysisContext2 = AnalysisContextFactory.contextWithCore();
+ }
+
+ /**
+ * Reset the analysis context to have the given options applied.
+ *
+ * @param options the analysis options to be applied to the context
+ */
+ void resetWithOptions(AnalysisOptions options) {
+ analysisContext2 =
+ AnalysisContextFactory.contextWithCoreAndOptions(options);
+ }
+
+ /**
+ * Given a library and all of its parts, resolve the contents of the library and the contents of
+ * the parts. This assumes that the sources for the library and its parts have already been added
+ * to the content provider using the method [addNamedSource].
+ *
+ * @param librarySource the source for the compilation unit that defines the library
+ * @return the element representing the resolved library
+ * @throws AnalysisException if the analysis could not be performed
+ */
+ LibraryElement resolve2(Source librarySource) =>
+ analysisContext2.computeLibraryElement(librarySource);
+
+ /**
+ * Return the resolved compilation unit corresponding to the given source in the given library.
+ *
+ * @param source the source of the compilation unit to be returned
+ * @param library the library in which the compilation unit is to be resolved
+ * @return the resolved compilation unit
+ * @throws Exception if the compilation unit could not be resolved
+ */
+ CompilationUnit resolveCompilationUnit(
+ Source source, LibraryElement library) =>
+ analysisContext2.resolveCompilationUnit(source, library);
+
+ CompilationUnit resolveSource(String sourceText) =>
+ resolveSource2("/test.dart", sourceText);
+
+ CompilationUnit resolveSource2(String fileName, String sourceText) {
+ Source source = addNamedSource(fileName, sourceText);
+ LibraryElement library = analysisContext.computeLibraryElement(source);
+ return analysisContext.resolveCompilationUnit(source, library);
+ }
+
+ Source resolveSources(List<String> sourceTexts) {
+ for (int i = 0; i < sourceTexts.length; i++) {
+ CompilationUnit unit =
+ resolveSource2("/lib${i + 1}.dart", sourceTexts[i]);
+ // reference the source if this is the last source
+ if (i + 1 == sourceTexts.length) {
+ return unit.element.source;
+ }
+ }
+ return null;
+ }
+
+ void resolveWithAndWithoutExperimental(
+ List<String> strSources,
+ List<ErrorCode> codesWithoutExperimental,
+ List<ErrorCode> codesWithExperimental) {
+ // Setup analysis context as non-experimental
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+// options.enableDeferredLoading = false;
+ resetWithOptions(options);
+ // Analysis and assertions
+ Source source = resolveSources(strSources);
+ assertErrors(source, codesWithoutExperimental);
+ verify([source]);
+ // Setup analysis context as experimental
+ reset();
+ // Analysis and assertions
+ source = resolveSources(strSources);
+ assertErrors(source, codesWithExperimental);
+ verify([source]);
+ }
+
+ void resolveWithErrors(List<String> strSources, List<ErrorCode> codes) {
+ // Analysis and assertions
+ Source source = resolveSources(strSources);
+ assertErrors(source, codes);
+ verify([source]);
+ }
+
+ @override
+ void setUp() {
+ reset();
+ }
+
+ @override
+ void tearDown() {
+ analysisContext2 = null;
+ super.tearDown();
+ }
+
+ /**
+ * Verify that all of the identifiers in the compilation units associated with
+ * the given [sources] have been resolved.
+ */
+ void verify(List<Source> sources) {
+ ResolutionVerifier verifier = new ResolutionVerifier();
+ for (Source source in sources) {
+ List<Source> libraries = analysisContext2.getLibrariesContaining(source);
+ for (Source library in libraries) {
+ analysisContext2
+ .resolveCompilationUnit2(source, library)
+ .accept(verifier);
+ }
+ }
+ verifier.assertResolved();
+ }
+
+ /**
+ * @param code the code that assigns the value to the variable "v", no matter how. We check that
+ * "v" has expected static and propagated type.
+ */
+ void _assertPropagatedAssignedType(String code, DartType expectedStaticType,
+ DartType expectedPropagatedType) {
+ SimpleIdentifier identifier = _findMarkedIdentifier(code, "v = ");
+ expect(identifier.staticType, same(expectedStaticType));
+ expect(identifier.propagatedType, same(expectedPropagatedType));
+ }
+
+ /**
+ * @param code the code that iterates using variable "v". We check that
+ * "v" has expected static and propagated type.
+ */
+ void _assertPropagatedIterationType(String code, DartType expectedStaticType,
+ DartType expectedPropagatedType) {
+ SimpleIdentifier identifier = _findMarkedIdentifier(code, "v in ");
+ expect(identifier.staticType, same(expectedStaticType));
+ expect(identifier.propagatedType, same(expectedPropagatedType));
+ }
+
+ /**
+ * Check the static and propagated types of the expression marked with "; // marker" comment.
+ *
+ * @param code source code to analyze, with the expression to check marked with "// marker".
+ * @param expectedStaticType if non-null, check actual static type is equal to this.
+ * @param expectedPropagatedType if non-null, check actual static type is equal to this.
+ * @throws Exception
+ */
+ void _assertTypeOfMarkedExpression(String code, DartType expectedStaticType,
+ DartType expectedPropagatedType) {
+ SimpleIdentifier identifier = _findMarkedIdentifier(code, "; // marker");
+ if (expectedStaticType != null) {
+ expect(identifier.staticType, expectedStaticType);
+ }
+ expect(identifier.propagatedType, expectedPropagatedType);
+ }
+
+ /**
+ * Create a source object representing a file with the given [fileName] and
+ * give it an empty content. Return the source that was created.
+ */
+ FileBasedSource _createNamedSource(String fileName) {
+ FileBasedSource source =
+ new FileBasedSource(FileUtilities2.createFile(fileName));
+ analysisContext2.setContents(source, "");
+ return source;
+ }
+
+ /**
+ * Return the `SimpleIdentifier` marked by `marker`. The source code must have no
+ * errors and be verifiable.
+ *
+ * @param code source code to analyze.
+ * @param marker marker identifying sought after expression in source code.
+ * @return expression marked by the marker.
+ * @throws Exception
+ */
+ SimpleIdentifier _findMarkedIdentifier(String code, String marker) {
+ try {
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ // Could generalize this further by making [SimpleIdentifier.class] a
+ // parameter.
+ return EngineTestCase.findNode(
+ unit, code, marker, (node) => node is SimpleIdentifier);
+ } catch (exception) {
+ // Is there a better exception to throw here? The point is that an
+ // assertion failure here should be a failure, in both "test_*" and
+ // "fail_*" tests. However, an assertion failure is success for the
+ // purpose of "fail_*" tests, so without catching them here "fail_*" tests
+ // can succeed by failing for the wrong reason.
+ throw new JavaException("Unexexpected assertion failure: $exception");
+ }
+ }
+}
+
+class Scope_EnclosedScopeTest_test_define_duplicate extends Scope {
+ GatheringErrorListener listener;
+
+ Scope_EnclosedScopeTest_test_define_duplicate(this.listener) : super();
+
+ @override
+ AnalysisErrorListener get errorListener => listener;
+
+ @override
+ Element internalLookup(Identifier identifier, String name,
+ LibraryElement referencingLibrary) =>
+ null;
+}
+
+class Scope_EnclosedScopeTest_test_define_normal extends Scope {
+ GatheringErrorListener listener;
+
+ Scope_EnclosedScopeTest_test_define_normal(this.listener) : super();
+
+ @override
+ AnalysisErrorListener get errorListener => listener;
+
+ @override
+ Element internalLookup(Identifier identifier, String name,
+ LibraryElement referencingLibrary) =>
+ null;
+}
+
+@reflectiveTest
+class ScopeTest extends ResolverTestCase {
+ void test_define_duplicate() {
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ ScopeTest_TestScope scope = new ScopeTest_TestScope(errorListener);
+ VariableElement element1 =
+ ElementFactory.localVariableElement(AstFactory.identifier3("v1"));
+ VariableElement element2 =
+ ElementFactory.localVariableElement(AstFactory.identifier3("v1"));
+ scope.define(element1);
+ scope.define(element2);
+ errorListener.assertErrorsWithSeverities([ErrorSeverity.ERROR]);
+ }
+
+ void test_define_normal() {
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ ScopeTest_TestScope scope = new ScopeTest_TestScope(errorListener);
+ VariableElement element1 =
+ ElementFactory.localVariableElement(AstFactory.identifier3("v1"));
+ VariableElement element2 =
+ ElementFactory.localVariableElement(AstFactory.identifier3("v2"));
+ scope.define(element1);
+ scope.define(element2);
+ errorListener.assertNoErrors();
+ }
+
+ void test_getErrorListener() {
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ ScopeTest_TestScope scope = new ScopeTest_TestScope(errorListener);
+ expect(scope.errorListener, errorListener);
+ }
+
+ void test_isPrivateName_nonPrivate() {
+ expect(Scope.isPrivateName("Public"), isFalse);
+ }
+
+ void test_isPrivateName_private() {
+ expect(Scope.isPrivateName("_Private"), isTrue);
+ }
+}
+
+/**
+ * A non-abstract subclass that can be used for testing purposes.
+ */
+class ScopeTest_TestScope extends Scope {
+ /**
+ * The listener that is to be informed when an error is encountered.
+ */
+ final AnalysisErrorListener errorListener;
+
+ ScopeTest_TestScope(this.errorListener);
+
+ @override
+ Element internalLookup(Identifier identifier, String name,
+ LibraryElement referencingLibrary) =>
+ localLookup(name, referencingLibrary);
+}
+
+@reflectiveTest
+class SimpleResolverTest extends ResolverTestCase {
+ void fail_getter_and_setter_fromMixins_property_access() {
+ // TODO(paulberry): it appears that auxiliaryElements isn't properly set on
+ // a SimpleIdentifier that's inside a property access. This bug should be
+ // fixed.
+ Source source = addSource('''
+class B {}
+class M1 {
+ get x => null;
+ set x(value) {}
+}
+class M2 {
+ get x => null;
+ set x(value) {}
+}
+class C extends B with M1, M2 {}
+void main() {
+ new C().x += 1;
+}
+''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ // Verify that both the getter and setter for "x" in "new C().x" refer to
+ // the accessors defined in M2.
+ FunctionDeclaration main =
+ library.definingCompilationUnit.functions[0].computeNode();
+ BlockFunctionBody body = main.functionExpression.body;
+ ExpressionStatement stmt = body.block.statements[0];
+ AssignmentExpression assignment = stmt.expression;
+ PropertyAccess propertyAccess = assignment.leftHandSide;
+ expect(
+ propertyAccess.propertyName.staticElement.enclosingElement.name, 'M2');
+ expect(
+ propertyAccess
+ .propertyName.auxiliaryElements.staticElement.enclosingElement.name,
+ 'M2');
+ }
+
+ void fail_staticInvocation() {
+ Source source = addSource(r'''
+class A {
+ static int get g => (a,b) => 0;
+}
+class B {
+ f() {
+ A.g(1,0);
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_argumentResolution_required_matching() {
+ Source source = addSource(r'''
+class A {
+ void f() {
+ g(1, 2, 3);
+ }
+ void g(a, b, c) {}
+}''');
+ _validateArgumentResolution(source, [0, 1, 2]);
+ }
+
+ void test_argumentResolution_required_tooFew() {
+ Source source = addSource(r'''
+class A {
+ void f() {
+ g(1, 2);
+ }
+ void g(a, b, c) {}
+}''');
+ _validateArgumentResolution(source, [0, 1]);
+ }
+
+ void test_argumentResolution_required_tooMany() {
+ Source source = addSource(r'''
+class A {
+ void f() {
+ g(1, 2, 3);
+ }
+ void g(a, b) {}
+}''');
+ _validateArgumentResolution(source, [0, 1, -1]);
+ }
+
+ void test_argumentResolution_requiredAndNamed_extra() {
+ Source source = addSource(r'''
+class A {
+ void f() {
+ g(1, 2, c: 3, d: 4);
+ }
+ void g(a, b, {c}) {}
+}''');
+ _validateArgumentResolution(source, [0, 1, 2, -1]);
+ }
+
+ void test_argumentResolution_requiredAndNamed_matching() {
+ Source source = addSource(r'''
+class A {
+ void f() {
+ g(1, 2, c: 3);
+ }
+ void g(a, b, {c}) {}
+}''');
+ _validateArgumentResolution(source, [0, 1, 2]);
+ }
+
+ void test_argumentResolution_requiredAndNamed_missing() {
+ Source source = addSource(r'''
+class A {
+ void f() {
+ g(1, 2, d: 3);
+ }
+ void g(a, b, {c, d}) {}
+}''');
+ _validateArgumentResolution(source, [0, 1, 3]);
+ }
+
+ void test_argumentResolution_requiredAndPositional_fewer() {
+ Source source = addSource(r'''
+class A {
+ void f() {
+ g(1, 2, 3);
+ }
+ void g(a, b, [c, d]) {}
+}''');
+ _validateArgumentResolution(source, [0, 1, 2]);
+ }
+
+ void test_argumentResolution_requiredAndPositional_matching() {
+ Source source = addSource(r'''
+class A {
+ void f() {
+ g(1, 2, 3, 4);
+ }
+ void g(a, b, [c, d]) {}
+}''');
+ _validateArgumentResolution(source, [0, 1, 2, 3]);
+ }
+
+ void test_argumentResolution_requiredAndPositional_more() {
+ Source source = addSource(r'''
+class A {
+ void f() {
+ g(1, 2, 3, 4);
+ }
+ void g(a, b, [c]) {}
+}''');
+ _validateArgumentResolution(source, [0, 1, 2, -1]);
+ }
+
+ void test_argumentResolution_setter_propagated() {
+ Source source = addSource(r'''
+main() {
+ var a = new A();
+ a.sss = 0;
+}
+class A {
+ set sss(x) {}
+}''');
+ LibraryElement library = resolve2(source);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ // find "a.sss = 0"
+ AssignmentExpression assignment;
+ {
+ FunctionElement mainElement = unit.functions[0];
+ FunctionBody mainBody = mainElement.computeNode().functionExpression.body;
+ Statement statement = (mainBody as BlockFunctionBody).block.statements[1];
+ ExpressionStatement expressionStatement =
+ statement as ExpressionStatement;
+ assignment = expressionStatement.expression as AssignmentExpression;
+ }
+ // get parameter
+ Expression rhs = assignment.rightHandSide;
+ expect(rhs.staticParameterElement, isNull);
+ ParameterElement parameter = rhs.propagatedParameterElement;
+ expect(parameter, isNotNull);
+ expect(parameter.displayName, "x");
+ // validate
+ ClassElement classA = unit.types[0];
+ PropertyAccessorElement setter = classA.accessors[0];
+ expect(setter.parameters[0], same(parameter));
+ }
+
+ void test_argumentResolution_setter_propagated_propertyAccess() {
+ Source source = addSource(r'''
+main() {
+ var a = new A();
+ a.b.sss = 0;
+}
+class A {
+ B b = new B();
+}
+class B {
+ set sss(x) {}
+}''');
+ LibraryElement library = resolve2(source);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ // find "a.b.sss = 0"
+ AssignmentExpression assignment;
+ {
+ FunctionElement mainElement = unit.functions[0];
+ FunctionBody mainBody = mainElement.computeNode().functionExpression.body;
+ Statement statement = (mainBody as BlockFunctionBody).block.statements[1];
+ ExpressionStatement expressionStatement =
+ statement as ExpressionStatement;
+ assignment = expressionStatement.expression as AssignmentExpression;
+ }
+ // get parameter
+ Expression rhs = assignment.rightHandSide;
+ expect(rhs.staticParameterElement, isNull);
+ ParameterElement parameter = rhs.propagatedParameterElement;
+ expect(parameter, isNotNull);
+ expect(parameter.displayName, "x");
+ // validate
+ ClassElement classB = unit.types[1];
+ PropertyAccessorElement setter = classB.accessors[0];
+ expect(setter.parameters[0], same(parameter));
+ }
+
+ void test_argumentResolution_setter_static() {
+ Source source = addSource(r'''
+main() {
+ A a = new A();
+ a.sss = 0;
+}
+class A {
+ set sss(x) {}
+}''');
+ LibraryElement library = resolve2(source);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ // find "a.sss = 0"
+ AssignmentExpression assignment;
+ {
+ FunctionElement mainElement = unit.functions[0];
+ FunctionBody mainBody = mainElement.computeNode().functionExpression.body;
+ Statement statement = (mainBody as BlockFunctionBody).block.statements[1];
+ ExpressionStatement expressionStatement =
+ statement as ExpressionStatement;
+ assignment = expressionStatement.expression as AssignmentExpression;
+ }
+ // get parameter
+ Expression rhs = assignment.rightHandSide;
+ ParameterElement parameter = rhs.staticParameterElement;
+ expect(parameter, isNotNull);
+ expect(parameter.displayName, "x");
+ // validate
+ ClassElement classA = unit.types[0];
+ PropertyAccessorElement setter = classA.accessors[0];
+ expect(setter.parameters[0], same(parameter));
+ }
+
+ void test_argumentResolution_setter_static_propertyAccess() {
+ Source source = addSource(r'''
+main() {
+ A a = new A();
+ a.b.sss = 0;
+}
+class A {
+ B b = new B();
+}
+class B {
+ set sss(x) {}
+}''');
+ LibraryElement library = resolve2(source);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ // find "a.b.sss = 0"
+ AssignmentExpression assignment;
+ {
+ FunctionElement mainElement = unit.functions[0];
+ FunctionBody mainBody = mainElement.computeNode().functionExpression.body;
+ Statement statement = (mainBody as BlockFunctionBody).block.statements[1];
+ ExpressionStatement expressionStatement =
+ statement as ExpressionStatement;
+ assignment = expressionStatement.expression as AssignmentExpression;
+ }
+ // get parameter
+ Expression rhs = assignment.rightHandSide;
+ ParameterElement parameter = rhs.staticParameterElement;
+ expect(parameter, isNotNull);
+ expect(parameter.displayName, "x");
+ // validate
+ ClassElement classB = unit.types[1];
+ PropertyAccessorElement setter = classB.accessors[0];
+ expect(setter.parameters[0], same(parameter));
+ }
+
+ void test_breakTarget_labeled() {
+ // Verify that the target of the label is correctly found and is recorded
+ // as the unlabeled portion of the statement.
+ String text = r'''
+void f() {
+ loop1: while (true) {
+ loop2: for (int i = 0; i < 10; i++) {
+ break loop1;
+ break loop2;
+ }
+ }
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ WhileStatement whileStatement = EngineTestCase.findNode(
+ unit, text, 'while (true)', (n) => n is WhileStatement);
+ ForStatement forStatement =
+ EngineTestCase.findNode(unit, text, 'for', (n) => n is ForStatement);
+ BreakStatement break1 = EngineTestCase.findNode(
+ unit, text, 'break loop1', (n) => n is BreakStatement);
+ BreakStatement break2 = EngineTestCase.findNode(
+ unit, text, 'break loop2', (n) => n is BreakStatement);
+ expect(break1.target, same(whileStatement));
+ expect(break2.target, same(forStatement));
+ }
+
+ void test_breakTarget_unlabeledBreakFromDo() {
+ String text = r'''
+void f() {
+ do {
+ break;
+ } while (true);
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ DoStatement doStatement =
+ EngineTestCase.findNode(unit, text, 'do', (n) => n is DoStatement);
+ BreakStatement breakStatement = EngineTestCase.findNode(
+ unit, text, 'break', (n) => n is BreakStatement);
+ expect(breakStatement.target, same(doStatement));
+ }
+
+ void test_breakTarget_unlabeledBreakFromFor() {
+ String text = r'''
+void f() {
+ for (int i = 0; i < 10; i++) {
+ break;
+ }
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ ForStatement forStatement =
+ EngineTestCase.findNode(unit, text, 'for', (n) => n is ForStatement);
+ BreakStatement breakStatement = EngineTestCase.findNode(
+ unit, text, 'break', (n) => n is BreakStatement);
+ expect(breakStatement.target, same(forStatement));
+ }
+
+ void test_breakTarget_unlabeledBreakFromForEach() {
+ String text = r'''
+void f() {
+ for (x in []) {
+ break;
+ }
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ ForEachStatement forStatement = EngineTestCase.findNode(
+ unit, text, 'for', (n) => n is ForEachStatement);
+ BreakStatement breakStatement = EngineTestCase.findNode(
+ unit, text, 'break', (n) => n is BreakStatement);
+ expect(breakStatement.target, same(forStatement));
+ }
+
+ void test_breakTarget_unlabeledBreakFromSwitch() {
+ String text = r'''
+void f() {
+ while (true) {
+ switch (0) {
+ case 0:
+ break;
+ }
+ }
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ SwitchStatement switchStatement = EngineTestCase.findNode(
+ unit, text, 'switch', (n) => n is SwitchStatement);
+ BreakStatement breakStatement = EngineTestCase.findNode(
+ unit, text, 'break', (n) => n is BreakStatement);
+ expect(breakStatement.target, same(switchStatement));
+ }
+
+ void test_breakTarget_unlabeledBreakFromWhile() {
+ String text = r'''
+void f() {
+ while (true) {
+ break;
+ }
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ WhileStatement whileStatement = EngineTestCase.findNode(
+ unit, text, 'while', (n) => n is WhileStatement);
+ BreakStatement breakStatement = EngineTestCase.findNode(
+ unit, text, 'break', (n) => n is BreakStatement);
+ expect(breakStatement.target, same(whileStatement));
+ }
+
+ void test_breakTarget_unlabeledBreakToOuterFunction() {
+ // Verify that unlabeled break statements can't resolve to loops in an
+ // outer function.
+ String text = r'''
+void f() {
+ while (true) {
+ void g() {
+ break;
+ }
+ }
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ BreakStatement breakStatement = EngineTestCase.findNode(
+ unit, text, 'break', (n) => n is BreakStatement);
+ expect(breakStatement.target, isNull);
+ }
+
+ void test_class_definesCall() {
+ Source source = addSource(r'''
+class A {
+ int call(int x) { return x; }
+}
+int f(A a) {
+ return a(0);
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_class_extends_implements() {
+ Source source = addSource(r'''
+class A extends B implements C {}
+class B {}
+class C {}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_commentReference_class() {
+ Source source = addSource(r'''
+f() {}
+/** [A] [new A] [A.n] [new A.n] [m] [f] */
+class A {
+ A() {}
+ A.n() {}
+ m() {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_commentReference_parameter() {
+ Source source = addSource(r'''
+class A {
+ A() {}
+ A.n() {}
+ /** [e] [f] */
+ m(e, f()) {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_commentReference_singleLine() {
+ Source source = addSource(r'''
+/// [A]
+class A {}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_continueTarget_labeled() {
+ // Verify that the target of the label is correctly found and is recorded
+ // as the unlabeled portion of the statement.
+ String text = r'''
+void f() {
+ loop1: while (true) {
+ loop2: for (int i = 0; i < 10; i++) {
+ continue loop1;
+ continue loop2;
+ }
+ }
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ WhileStatement whileStatement = EngineTestCase.findNode(
+ unit, text, 'while (true)', (n) => n is WhileStatement);
+ ForStatement forStatement =
+ EngineTestCase.findNode(unit, text, 'for', (n) => n is ForStatement);
+ ContinueStatement continue1 = EngineTestCase.findNode(
+ unit, text, 'continue loop1', (n) => n is ContinueStatement);
+ ContinueStatement continue2 = EngineTestCase.findNode(
+ unit, text, 'continue loop2', (n) => n is ContinueStatement);
+ expect(continue1.target, same(whileStatement));
+ expect(continue2.target, same(forStatement));
+ }
+
+ void test_continueTarget_unlabeledContinueFromDo() {
+ String text = r'''
+void f() {
+ do {
+ continue;
+ } while (true);
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ DoStatement doStatement =
+ EngineTestCase.findNode(unit, text, 'do', (n) => n is DoStatement);
+ ContinueStatement continueStatement = EngineTestCase.findNode(
+ unit, text, 'continue', (n) => n is ContinueStatement);
+ expect(continueStatement.target, same(doStatement));
+ }
+
+ void test_continueTarget_unlabeledContinueFromFor() {
+ String text = r'''
+void f() {
+ for (int i = 0; i < 10; i++) {
+ continue;
+ }
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ ForStatement forStatement =
+ EngineTestCase.findNode(unit, text, 'for', (n) => n is ForStatement);
+ ContinueStatement continueStatement = EngineTestCase.findNode(
+ unit, text, 'continue', (n) => n is ContinueStatement);
+ expect(continueStatement.target, same(forStatement));
+ }
+
+ void test_continueTarget_unlabeledContinueFromForEach() {
+ String text = r'''
+void f() {
+ for (x in []) {
+ continue;
+ }
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ ForEachStatement forStatement = EngineTestCase.findNode(
+ unit, text, 'for', (n) => n is ForEachStatement);
+ ContinueStatement continueStatement = EngineTestCase.findNode(
+ unit, text, 'continue', (n) => n is ContinueStatement);
+ expect(continueStatement.target, same(forStatement));
+ }
+
+ void test_continueTarget_unlabeledContinueFromWhile() {
+ String text = r'''
+void f() {
+ while (true) {
+ continue;
+ }
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ WhileStatement whileStatement = EngineTestCase.findNode(
+ unit, text, 'while', (n) => n is WhileStatement);
+ ContinueStatement continueStatement = EngineTestCase.findNode(
+ unit, text, 'continue', (n) => n is ContinueStatement);
+ expect(continueStatement.target, same(whileStatement));
+ }
+
+ void test_continueTarget_unlabeledContinueSkipsSwitch() {
+ String text = r'''
+void f() {
+ while (true) {
+ switch (0) {
+ case 0:
+ continue;
+ }
+ }
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ WhileStatement whileStatement = EngineTestCase.findNode(
+ unit, text, 'while', (n) => n is WhileStatement);
+ ContinueStatement continueStatement = EngineTestCase.findNode(
+ unit, text, 'continue', (n) => n is ContinueStatement);
+ expect(continueStatement.target, same(whileStatement));
+ }
+
+ void test_continueTarget_unlabeledContinueToOuterFunction() {
+ // Verify that unlabeled continue statements can't resolve to loops in an
+ // outer function.
+ String text = r'''
+void f() {
+ while (true) {
+ void g() {
+ continue;
+ }
+ }
+}
+''';
+ CompilationUnit unit = resolveSource(text);
+ ContinueStatement continueStatement = EngineTestCase.findNode(
+ unit, text, 'continue', (n) => n is ContinueStatement);
+ expect(continueStatement.target, isNull);
+ }
+
+ void test_empty() {
+ Source source = addSource("");
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_entryPoint_exported() {
+ addNamedSource(
+ "/two.dart",
+ r'''
+library two;
+main() {}''');
+ Source source = addNamedSource(
+ "/one.dart",
+ r'''
+library one;
+export 'two.dart';''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ FunctionElement main = library.entryPoint;
+ expect(main, isNotNull);
+ expect(main.library, isNot(same(library)));
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_entryPoint_local() {
+ Source source = addNamedSource(
+ "/one.dart",
+ r'''
+library one;
+main() {}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ FunctionElement main = library.entryPoint;
+ expect(main, isNotNull);
+ expect(main.library, same(library));
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_entryPoint_none() {
+ Source source = addNamedSource("/one.dart", "library one;");
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ expect(library.entryPoint, isNull);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_enum_externalLibrary() {
+ addNamedSource(
+ "/my_lib.dart",
+ r'''
+library my_lib;
+enum EEE {A, B, C}''');
+ Source source = addSource(r'''
+import 'my_lib.dart';
+main() {
+ EEE e = null;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_extractedMethodAsConstant() {
+ Source source = addSource(r'''
+abstract class Comparable<T> {
+ int compareTo(T other);
+ static int compare(Comparable a, Comparable b) => a.compareTo(b);
+}
+class A {
+ void sort([compare = Comparable.compare]) {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_fieldFormalParameter() {
+ Source source = addSource(r'''
+class A {
+ int x;
+ A(this.x) {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_forEachLoops_nonConflicting() {
+ Source source = addSource(r'''
+f() {
+ List list = [1,2,3];
+ for (int x in list) {}
+ for (int x in list) {}
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_forLoops_nonConflicting() {
+ Source source = addSource(r'''
+f() {
+ for (int i = 0; i < 3; i++) {
+ }
+ for (int i = 0; i < 3; i++) {
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_functionTypeAlias() {
+ Source source = addSource(r'''
+typedef bool P(e);
+class A {
+ P p;
+ m(e) {
+ if (p(e)) {}
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_getter_and_setter_fromMixins_bare_identifier() {
+ Source source = addSource('''
+class B {}
+class M1 {
+ get x => null;
+ set x(value) {}
+}
+class M2 {
+ get x => null;
+ set x(value) {}
+}
+class C extends B with M1, M2 {
+ void f() {
+ x += 1;
+ }
+}
+''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ // Verify that both the getter and setter for "x" in C.f() refer to the
+ // accessors defined in M2.
+ ClassElement classC = library.definingCompilationUnit.types[3];
+ MethodDeclaration f = classC.getMethod('f').computeNode();
+ BlockFunctionBody body = f.body;
+ ExpressionStatement stmt = body.block.statements[0];
+ AssignmentExpression assignment = stmt.expression;
+ SimpleIdentifier leftHandSide = assignment.leftHandSide;
+ expect(leftHandSide.staticElement.enclosingElement.name, 'M2');
+ expect(leftHandSide.auxiliaryElements.staticElement.enclosingElement.name,
+ 'M2');
+ }
+
+ void test_getter_fromMixins_bare_identifier() {
+ Source source = addSource('''
+class B {}
+class M1 {
+ get x => null;
+}
+class M2 {
+ get x => null;
+}
+class C extends B with M1, M2 {
+ f() {
+ return x;
+ }
+}
+''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ // Verify that the getter for "x" in C.f() refers to the getter defined in
+ // M2.
+ ClassElement classC = library.definingCompilationUnit.types[3];
+ MethodDeclaration f = classC.getMethod('f').computeNode();
+ BlockFunctionBody body = f.body;
+ ReturnStatement stmt = body.block.statements[0];
+ SimpleIdentifier x = stmt.expression;
+ expect(x.staticElement.enclosingElement.name, 'M2');
+ }
+
+ void test_getter_fromMixins_property_access() {
+ Source source = addSource('''
+class B {}
+class M1 {
+ get x => null;
+}
+class M2 {
+ get x => null;
+}
+class C extends B with M1, M2 {}
+void main() {
+ var y = new C().x;
+}
+''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ // Verify that the getter for "x" in "new C().x" refers to the getter
+ // defined in M2.
+ FunctionDeclaration main =
+ library.definingCompilationUnit.functions[0].computeNode();
+ BlockFunctionBody body = main.functionExpression.body;
+ VariableDeclarationStatement stmt = body.block.statements[0];
+ PropertyAccess propertyAccess = stmt.variables.variables[0].initializer;
+ expect(
+ propertyAccess.propertyName.staticElement.enclosingElement.name, 'M2');
+ }
+
+ void test_getterAndSetterWithDifferentTypes() {
+ Source source = addSource(r'''
+class A {
+ int get f => 0;
+ void set f(String s) {}
+}
+g (A a) {
+ a.f = a.f.toString();
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(
+ source, [StaticWarningCode.MISMATCHED_GETTER_AND_SETTER_TYPES]);
+ verify([source]);
+ }
+
+ void test_hasReferenceToSuper() {
+ Source source = addSource(r'''
+class A {}
+class B {toString() => super.toString();}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ List<ClassElement> classes = unit.types;
+ expect(classes, hasLength(2));
+ expect(classes[0].hasReferenceToSuper, isFalse);
+ expect(classes[1].hasReferenceToSuper, isTrue);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_import_hide() {
+ addNamedSource(
+ "/lib1.dart",
+ r'''
+library lib1;
+set foo(value) {}
+class A {}''');
+ addNamedSource(
+ "/lib2.dart",
+ r'''
+library lib2;
+set foo(value) {}''');
+ Source source = addNamedSource(
+ "/lib3.dart",
+ r'''
+import 'lib1.dart' hide foo;
+import 'lib2.dart';
+
+main() {
+ foo = 0;
+}
+A a;''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_import_prefix() {
+ addNamedSource(
+ "/two.dart",
+ r'''
+library two;
+f(int x) {
+ return x * x;
+}''');
+ Source source = addNamedSource(
+ "/one.dart",
+ r'''
+library one;
+import 'two.dart' as _two;
+main() {
+ _two.f(0);
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_import_spaceInUri() {
+ addNamedSource(
+ "/sub folder/lib.dart",
+ r'''
+library lib;
+foo() {}''');
+ Source source = addNamedSource(
+ "/app.dart",
+ r'''
+import 'sub folder/lib.dart';
+
+main() {
+ foo();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_indexExpression_typeParameters() {
+ Source source = addSource(r'''
+f() {
+ List<int> a;
+ a[0];
+ List<List<int>> b;
+ b[0][0];
+ List<List<List<int>>> c;
+ c[0][0][0];
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_indexExpression_typeParameters_invalidAssignmentWarning() {
+ Source source = addSource(r'''
+f() {
+ List<List<int>> b;
+ b[0][0] = 'hi';
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+ verify([source]);
+ }
+
+ void test_indirectOperatorThroughCall() {
+ Source source = addSource(r'''
+class A {
+ B call() { return new B(); }
+}
+
+class B {
+ int operator [](int i) { return i; }
+}
+
+A f = new A();
+
+g(int x) {}
+
+main() {
+ g(f()[0]);
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_invoke_dynamicThroughGetter() {
+ Source source = addSource(r'''
+class A {
+ List get X => [() => 0];
+ m(A a) {
+ X.last;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_isValidMixin_badSuperclass() {
+ Source source = addSource(r'''
+class A extends B {}
+class B {}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ List<ClassElement> classes = unit.types;
+ expect(classes, hasLength(2));
+ expect(classes[0].isValidMixin, isFalse);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_isValidMixin_constructor() {
+ Source source = addSource(r'''
+class A {
+ A() {}
+}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ List<ClassElement> classes = unit.types;
+ expect(classes, hasLength(1));
+ expect(classes[0].isValidMixin, isFalse);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_isValidMixin_super() {
+ Source source = addSource(r'''
+class A {
+ toString() {
+ return super.toString();
+ }
+}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ List<ClassElement> classes = unit.types;
+ expect(classes, hasLength(1));
+ expect(classes[0].isValidMixin, isFalse);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_isValidMixin_valid() {
+ Source source = addSource("class A {}");
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ List<ClassElement> classes = unit.types;
+ expect(classes, hasLength(1));
+ expect(classes[0].isValidMixin, isTrue);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_labels_switch() {
+ Source source = addSource(r'''
+void doSwitch(int target) {
+ switch (target) {
+ l0: case 0:
+ continue l1;
+ l1: case 1:
+ continue l0;
+ default:
+ continue l1;
+ }
+}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_localVariable_types_invoked() {
+ Source source = addSource(r'''
+const A = null;
+main() {
+ var myVar = (int p) => 'foo';
+ myVar(42);
+}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnit unit =
+ analysisContext.resolveCompilationUnit(source, library);
+ expect(unit, isNotNull);
+ List<bool> found = [false];
+ List<CaughtException> thrownException = new List<CaughtException>(1);
+ unit.accept(new _SimpleResolverTest_localVariable_types_invoked(
+ this, found, thrownException));
+ if (thrownException[0] != null) {
+ throw new AnalysisException(
+ "Exception", new CaughtException(thrownException[0], null));
+ }
+ expect(found[0], isTrue);
+ }
+
+ void test_metadata_class() {
+ Source source = addSource(r'''
+const A = null;
+@A class C<A> {}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unitElement = library.definingCompilationUnit;
+ expect(unitElement, isNotNull);
+ List<ClassElement> classes = unitElement.types;
+ expect(classes, hasLength(1));
+ List<ElementAnnotation> annotations = classes[0].metadata;
+ expect(annotations, hasLength(1));
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ NodeList<CompilationUnitMember> declarations = unit.declarations;
+ expect(declarations, hasLength(2));
+ Element expectedElement = (declarations[0] as TopLevelVariableDeclaration)
+ .variables
+ .variables[0].name.staticElement;
+ EngineTestCase.assertInstanceOf((obj) => obj is PropertyInducingElement,
+ PropertyInducingElement, expectedElement);
+ expectedElement = (expectedElement as PropertyInducingElement).getter;
+ Element actualElement =
+ (declarations[1] as ClassDeclaration).metadata[0].name.staticElement;
+ expect(actualElement, same(expectedElement));
+ }
+
+ void test_metadata_field() {
+ Source source = addSource(r'''
+const A = null;
+class C {
+ @A int f;
+}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ List<ClassElement> classes = unit.types;
+ expect(classes, hasLength(1));
+ FieldElement field = classes[0].fields[0];
+ List<ElementAnnotation> annotations = field.metadata;
+ expect(annotations, hasLength(1));
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_metadata_fieldFormalParameter() {
+ Source source = addSource(r'''
+const A = null;
+class C {
+ int f;
+ C(@A this.f);
+}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ List<ClassElement> classes = unit.types;
+ expect(classes, hasLength(1));
+ List<ConstructorElement> constructors = classes[0].constructors;
+ expect(constructors, hasLength(1));
+ List<ParameterElement> parameters = constructors[0].parameters;
+ expect(parameters, hasLength(1));
+ List<ElementAnnotation> annotations = parameters[0].metadata;
+ expect(annotations, hasLength(1));
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_metadata_function() {
+ Source source = addSource(r'''
+const A = null;
+@A f() {}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ List<FunctionElement> functions = unit.functions;
+ expect(functions, hasLength(1));
+ List<ElementAnnotation> annotations = functions[0].metadata;
+ expect(annotations, hasLength(1));
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_metadata_functionTypedParameter() {
+ Source source = addSource(r'''
+const A = null;
+f(@A int p(int x)) {}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ List<FunctionElement> functions = unit.functions;
+ expect(functions, hasLength(1));
+ List<ParameterElement> parameters = functions[0].parameters;
+ expect(parameters, hasLength(1));
+ List<ElementAnnotation> annotations1 = parameters[0].metadata;
+ expect(annotations1, hasLength(1));
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_metadata_libraryDirective() {
+ Source source = addSource(r'''
+@A library lib;
+const A = null;''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ List<ElementAnnotation> annotations = library.metadata;
+ expect(annotations, hasLength(1));
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_metadata_method() {
+ Source source = addSource(r'''
+const A = null;
+class C {
+ @A void m() {}
+}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ List<ClassElement> classes = unit.types;
+ expect(classes, hasLength(1));
+ MethodElement method = classes[0].methods[0];
+ List<ElementAnnotation> annotations = method.metadata;
+ expect(annotations, hasLength(1));
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_metadata_namedParameter() {
+ Source source = addSource(r'''
+const A = null;
+f({@A int p : 0}) {}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ List<FunctionElement> functions = unit.functions;
+ expect(functions, hasLength(1));
+ List<ParameterElement> parameters = functions[0].parameters;
+ expect(parameters, hasLength(1));
+ List<ElementAnnotation> annotations1 = parameters[0].metadata;
+ expect(annotations1, hasLength(1));
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_metadata_positionalParameter() {
+ Source source = addSource(r'''
+const A = null;
+f([@A int p = 0]) {}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ List<FunctionElement> functions = unit.functions;
+ expect(functions, hasLength(1));
+ List<ParameterElement> parameters = functions[0].parameters;
+ expect(parameters, hasLength(1));
+ List<ElementAnnotation> annotations1 = parameters[0].metadata;
+ expect(annotations1, hasLength(1));
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_metadata_simpleParameter() {
+ Source source = addSource(r'''
+const A = null;
+f(@A p1, @A int p2) {}''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unit = library.definingCompilationUnit;
+ expect(unit, isNotNull);
+ List<FunctionElement> functions = unit.functions;
+ expect(functions, hasLength(1));
+ List<ParameterElement> parameters = functions[0].parameters;
+ expect(parameters, hasLength(2));
+ List<ElementAnnotation> annotations1 = parameters[0].metadata;
+ expect(annotations1, hasLength(1));
+ List<ElementAnnotation> annotations2 = parameters[1].metadata;
+ expect(annotations2, hasLength(1));
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_metadata_typedef() {
+ Source source = addSource(r'''
+const A = null;
+@A typedef F<A>();''');
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ CompilationUnitElement unitElement = library.definingCompilationUnit;
+ expect(unitElement, isNotNull);
+ List<FunctionTypeAliasElement> aliases = unitElement.functionTypeAliases;
+ expect(aliases, hasLength(1));
+ List<ElementAnnotation> annotations = aliases[0].metadata;
+ expect(annotations, hasLength(1));
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ NodeList<CompilationUnitMember> declarations = unit.declarations;
+ expect(declarations, hasLength(2));
+ Element expectedElement = (declarations[0] as TopLevelVariableDeclaration)
+ .variables
+ .variables[0].name.staticElement;
+ EngineTestCase.assertInstanceOf((obj) => obj is PropertyInducingElement,
+ PropertyInducingElement, expectedElement);
+ expectedElement = (expectedElement as PropertyInducingElement).getter;
+ Element actualElement =
+ (declarations[1] as FunctionTypeAlias).metadata[0].name.staticElement;
+ expect(actualElement, same(expectedElement));
+ }
+
+ void test_method_fromMixin() {
+ Source source = addSource(r'''
+class B {
+ bar() => 1;
+}
+class A {
+ foo() => 2;
+}
+
+class C extends B with A {
+ bar() => super.bar();
+ foo() => super.foo();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_method_fromMixins() {
+ Source source = addSource('''
+class B {}
+class M1 {
+ void f() {}
+}
+class M2 {
+ void f() {}
+}
+class C extends B with M1, M2 {}
+void main() {
+ new C().f();
+}
+''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ // Verify that the "f" in "new C().f()" refers to the "f" defined in M2.
+ FunctionDeclaration main =
+ library.definingCompilationUnit.functions[0].computeNode();
+ BlockFunctionBody body = main.functionExpression.body;
+ ExpressionStatement stmt = body.block.statements[0];
+ MethodInvocation expr = stmt.expression;
+ expect(expr.methodName.staticElement.enclosingElement.name, 'M2');
+ }
+
+ void test_method_fromMixins_bare_identifier() {
+ Source source = addSource('''
+class B {}
+class M1 {
+ void f() {}
+}
+class M2 {
+ void f() {}
+}
+class C extends B with M1, M2 {
+ void g() {
+ f();
+ }
+}
+''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ // Verify that the call to f() in C.g() refers to the method defined in M2.
+ ClassElement classC = library.definingCompilationUnit.types[3];
+ MethodDeclaration g = classC.getMethod('g').computeNode();
+ BlockFunctionBody body = g.body;
+ ExpressionStatement stmt = body.block.statements[0];
+ MethodInvocation invocation = stmt.expression;
+ SimpleIdentifier methodName = invocation.methodName;
+ expect(methodName.staticElement.enclosingElement.name, 'M2');
+ }
+
+ void test_method_fromMixins_invked_from_outside_class() {
+ Source source = addSource('''
+class B {}
+class M1 {
+ void f() {}
+}
+class M2 {
+ void f() {}
+}
+class C extends B with M1, M2 {}
+void main() {
+ new C().f();
+}
+''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ // Verify that the call to f() in "new C().f()" refers to the method
+ // defined in M2.
+ FunctionDeclaration main =
+ library.definingCompilationUnit.functions[0].computeNode();
+ BlockFunctionBody body = main.functionExpression.body;
+ ExpressionStatement stmt = body.block.statements[0];
+ MethodInvocation invocation = stmt.expression;
+ expect(invocation.methodName.staticElement.enclosingElement.name, 'M2');
+ }
+
+ void test_method_fromSuperclassMixin() {
+ Source source = addSource(r'''
+class A {
+ void m1() {}
+}
+class B extends Object with A {
+}
+class C extends B {
+}
+f(C c) {
+ c.m1();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_methodCascades() {
+ Source source = addSource(r'''
+class A {
+ void m1() {}
+ void m2() {}
+ void m() {
+ A a = new A();
+ a..m1()
+ ..m2();
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_methodCascades_withSetter() {
+ Source source = addSource(r'''
+class A {
+ String name;
+ void m1() {}
+ void m2() {}
+ void m() {
+ A a = new A();
+ a..m1()
+ ..name = 'name'
+ ..m2();
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ // failing with error code: INVOCATION_OF_NON_FUNCTION
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_resolveAgainstNull() {
+ Source source = addSource(r'''
+f(var p) {
+ return null == p;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_setter_fromMixins_bare_identifier() {
+ Source source = addSource('''
+class B {}
+class M1 {
+ set x(value) {}
+}
+class M2 {
+ set x(value) {}
+}
+class C extends B with M1, M2 {
+ void f() {
+ x = 1;
+ }
+}
+''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ // Verify that the setter for "x" in C.f() refers to the setter defined in
+ // M2.
+ ClassElement classC = library.definingCompilationUnit.types[3];
+ MethodDeclaration f = classC.getMethod('f').computeNode();
+ BlockFunctionBody body = f.body;
+ ExpressionStatement stmt = body.block.statements[0];
+ AssignmentExpression assignment = stmt.expression;
+ SimpleIdentifier leftHandSide = assignment.leftHandSide;
+ expect(leftHandSide.staticElement.enclosingElement.name, 'M2');
+ }
+
+ void test_setter_fromMixins_property_access() {
+ Source source = addSource('''
+class B {}
+class M1 {
+ set x(value) {}
+}
+class M2 {
+ set x(value) {}
+}
+class C extends B with M1, M2 {}
+void main() {
+ new C().x = 1;
+}
+''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ // Verify that the setter for "x" in "new C().x" refers to the setter
+ // defined in M2.
+ FunctionDeclaration main =
+ library.definingCompilationUnit.functions[0].computeNode();
+ BlockFunctionBody body = main.functionExpression.body;
+ ExpressionStatement stmt = body.block.statements[0];
+ AssignmentExpression assignment = stmt.expression;
+ PropertyAccess propertyAccess = assignment.leftHandSide;
+ expect(
+ propertyAccess.propertyName.staticElement.enclosingElement.name, 'M2');
+ }
+
+ void test_setter_inherited() {
+ Source source = addSource(r'''
+class A {
+ int get x => 0;
+ set x(int p) {}
+}
+class B extends A {
+ int get x => super.x == null ? 0 : super.x;
+ int f() => x = 1;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_setter_static() {
+ Source source = addSource(r'''
+set s(x) {
+}
+
+main() {
+ s = 123;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ /**
+ * Resolve the given source and verify that the arguments in a specific method invocation were
+ * correctly resolved.
+ *
+ * The source is expected to be source for a compilation unit, the first declaration is expected
+ * to be a class, the first member of which is expected to be a method with a block body, and the
+ * first statement in the body is expected to be an expression statement whose expression is a
+ * method invocation. It is the arguments to that method invocation that are tested. The method
+ * invocation can contain errors.
+ *
+ * The arguments were resolved correctly if the number of expressions in the list matches the
+ * length of the array of indices and if, for each index in the array of indices, the parameter to
+ * which the argument expression was resolved is the parameter in the invoked method's list of
+ * parameters at that index. Arguments that should not be resolved to a parameter because of an
+ * error can be denoted by including a negative index in the array of indices.
+ *
+ * @param source the source to be resolved
+ * @param indices the array of indices used to associate arguments with parameters
+ * @throws Exception if the source could not be resolved or if the structure of the source is not
+ * valid
+ */
+ void _validateArgumentResolution(Source source, List<int> indices) {
+ LibraryElement library = resolve2(source);
+ expect(library, isNotNull);
+ ClassElement classElement = library.definingCompilationUnit.types[0];
+ List<ParameterElement> parameters = classElement.methods[1].parameters;
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ expect(unit, isNotNull);
+ ClassDeclaration classDeclaration =
+ unit.declarations[0] as ClassDeclaration;
+ MethodDeclaration methodDeclaration =
+ classDeclaration.members[0] as MethodDeclaration;
+ Block block = (methodDeclaration.body as BlockFunctionBody).block;
+ ExpressionStatement statement = block.statements[0] as ExpressionStatement;
+ MethodInvocation invocation = statement.expression as MethodInvocation;
+ NodeList<Expression> arguments = invocation.argumentList.arguments;
+ int argumentCount = arguments.length;
+ expect(argumentCount, indices.length);
+ for (int i = 0; i < argumentCount; i++) {
+ Expression argument = arguments[i];
+ ParameterElement element = argument.staticParameterElement;
+ int index = indices[i];
+ if (index < 0) {
+ expect(element, isNull);
+ } else {
+ expect(element, same(parameters[index]));
+ }
+ }
+ }
+}
+
+class SourceContainer_ChangeSetTest_test_toString implements SourceContainer {
+ @override
+ bool contains(Source source) => false;
+}
+
+/**
+ * Like [StaticTypeAnalyzerTest], but as end-to-end tests.
+ */
+@reflectiveTest
+class StaticTypeAnalyzer2Test extends _StaticTypeAnalyzer2TestShared {
+ void test_FunctionExpressionInvocation_block() {
+ String code = r'''
+main() {
+ var foo = (() { return 1; })();
+}
+''';
+ _resolveTestUnit(code);
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.isDynamic, isTrue);
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_FunctionExpressionInvocation_curried() {
+ String code = r'''
+typedef int F();
+F f() => null;
+main() {
+ var foo = f()();
+}
+''';
+ _resolveTestUnit(code);
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'int');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_FunctionExpressionInvocation_expression() {
+ String code = r'''
+main() {
+ var foo = (() => 1)();
+}
+''';
+ _resolveTestUnit(code);
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'int');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_MethodInvocation_nameType_localVariable() {
+ String code = r"""
+typedef Foo();
+main() {
+ Foo foo;
+ foo();
+}
+""";
+ _resolveTestUnit(code);
+ // "foo" should be resolved to the "Foo" type
+ SimpleIdentifier identifier = _findIdentifier("foo();");
+ DartType type = identifier.staticType;
+ expect(type, new isInstanceOf<FunctionType>());
+ }
+
+ void test_MethodInvocation_nameType_parameter_FunctionTypeAlias() {
+ String code = r"""
+typedef Foo();
+main(Foo foo) {
+ foo();
+}
+""";
+ _resolveTestUnit(code);
+ // "foo" should be resolved to the "Foo" type
+ SimpleIdentifier identifier = _findIdentifier("foo();");
+ DartType type = identifier.staticType;
+ expect(type, new isInstanceOf<FunctionType>());
+ }
+
+ void test_MethodInvocation_nameType_parameter_propagatedType() {
+ String code = r"""
+typedef Foo();
+main(p) {
+ if (p is Foo) {
+ p();
+ }
+}
+""";
+ _resolveTestUnit(code);
+ SimpleIdentifier identifier = _findIdentifier("p()");
+ expect(identifier.staticType, DynamicTypeImpl.instance);
+ {
+ FunctionType type = identifier.propagatedType;
+ expect(type, isNotNull);
+ expect(type.name, 'Foo');
+ }
+ }
+}
+
+@reflectiveTest
+class StaticTypeAnalyzerTest extends EngineTestCase {
+ /**
+ * The error listener to which errors will be reported.
+ */
+ GatheringErrorListener _listener;
+
+ /**
+ * The resolver visitor used to create the analyzer.
+ */
+ ResolverVisitor _visitor;
+
+ /**
+ * The analyzer being used to analyze the test cases.
+ */
+ StaticTypeAnalyzer _analyzer;
+
+ /**
+ * The type provider used to access the types.
+ */
+ TestTypeProvider _typeProvider;
+
+ void fail_visitFunctionExpressionInvocation() {
+ fail("Not yet tested");
+ _listener.assertNoErrors();
+ }
+
+ void fail_visitMethodInvocation() {
+ fail("Not yet tested");
+ _listener.assertNoErrors();
+ }
+
+ void fail_visitSimpleIdentifier() {
+ fail("Not yet tested");
+ _listener.assertNoErrors();
+ }
+
+ @override
+ void setUp() {
+ _listener = new GatheringErrorListener();
+ _typeProvider = new TestTypeProvider();
+ _analyzer = _createAnalyzer();
+ }
+
+ void test_flatten_derived() {
+ // class Derived<T> extends Future<T> { ... }
+ ClassElementImpl derivedClass =
+ ElementFactory.classElement2('Derived', ['T']);
+ derivedClass.supertype = _typeProvider.futureType
+ .substitute4([derivedClass.typeParameters[0].type]);
+ InterfaceType intType = _typeProvider.intType;
+ DartType dynamicType = _typeProvider.dynamicType;
+ InterfaceType derivedIntType = derivedClass.type.substitute4([intType]);
+ // flatten(Derived) = dynamic
+ InterfaceType derivedDynamicType =
+ derivedClass.type.substitute4([dynamicType]);
+ expect(_flatten(derivedDynamicType), dynamicType);
+ // flatten(Derived<int>) = int
+ expect(_flatten(derivedIntType), intType);
+ // flatten(Derived<Derived>) = Derived
+ expect(_flatten(derivedClass.type.substitute4([derivedDynamicType])),
+ derivedDynamicType);
+ // flatten(Derived<Derived<int>>) = Derived<int>
+ expect(_flatten(derivedClass.type.substitute4([derivedIntType])),
+ derivedIntType);
+ }
+
+ void test_flatten_inhibit_recursion() {
+ // class A extends B
+ // class B extends A
+ ClassElementImpl classA = ElementFactory.classElement2('A', []);
+ ClassElementImpl classB = ElementFactory.classElement2('B', []);
+ classA.supertype = classB.type;
+ classB.supertype = classA.type;
+ // flatten(A) = A and flatten(B) = B, since neither class contains Future
+ // in its class hierarchy. Even though there is a loop in the class
+ // hierarchy, flatten() should terminate.
+ expect(_flatten(classA.type), classA.type);
+ expect(_flatten(classB.type), classB.type);
+ }
+
+ void test_flatten_related_derived_types() {
+ InterfaceType intType = _typeProvider.intType;
+ InterfaceType numType = _typeProvider.numType;
+ // class Derived<T> extends Future<T>
+ ClassElementImpl derivedClass =
+ ElementFactory.classElement2('Derived', ['T']);
+ derivedClass.supertype = _typeProvider.futureType
+ .substitute4([derivedClass.typeParameters[0].type]);
+ InterfaceType derivedType = derivedClass.type;
+ // class A extends Derived<int> implements Derived<num> { ... }
+ ClassElementImpl classA =
+ ElementFactory.classElement('A', derivedType.substitute4([intType]));
+ classA.interfaces = <InterfaceType>[
+ derivedType.substitute4([numType])
+ ];
+ // class B extends Future<num> implements Future<int> { ... }
+ ClassElementImpl classB =
+ ElementFactory.classElement('B', derivedType.substitute4([numType]));
+ classB.interfaces = <InterfaceType>[
+ derivedType.substitute4([intType])
+ ];
+ // flatten(A) = flatten(B) = int, since int is more specific than num.
+ // The code in flatten() that inhibits infinite recursion shouldn't be
+ // fooled by the fact that Derived appears twice in the type hierarchy.
+ expect(_flatten(classA.type), intType);
+ expect(_flatten(classB.type), intType);
+ }
+
+ void test_flatten_related_types() {
+ InterfaceType futureType = _typeProvider.futureType;
+ InterfaceType intType = _typeProvider.intType;
+ InterfaceType numType = _typeProvider.numType;
+ // class A extends Future<int> implements Future<num> { ... }
+ ClassElementImpl classA =
+ ElementFactory.classElement('A', futureType.substitute4([intType]));
+ classA.interfaces = <InterfaceType>[
+ futureType.substitute4([numType])
+ ];
+ // class B extends Future<num> implements Future<int> { ... }
+ ClassElementImpl classB =
+ ElementFactory.classElement('B', futureType.substitute4([numType]));
+ classB.interfaces = <InterfaceType>[
+ futureType.substitute4([intType])
+ ];
+ // flatten(A) = flatten(B) = int, since int is more specific than num.
+ expect(_flatten(classA.type), intType);
+ expect(_flatten(classB.type), intType);
+ }
+
+ void test_flatten_simple() {
+ InterfaceType intType = _typeProvider.intType;
+ DartType dynamicType = _typeProvider.dynamicType;
+ InterfaceType futureDynamicType = _typeProvider.futureDynamicType;
+ InterfaceType futureIntType =
+ _typeProvider.futureType.substitute4([intType]);
+ InterfaceType futureFutureDynamicType =
+ _typeProvider.futureType.substitute4([futureDynamicType]);
+ InterfaceType futureFutureIntType =
+ _typeProvider.futureType.substitute4([futureIntType]);
+ // flatten(int) = int
+ expect(_flatten(intType), intType);
+ // flatten(dynamic) = dynamic
+ expect(_flatten(dynamicType), dynamicType);
+ // flatten(Future) = dynamic
+ expect(_flatten(futureDynamicType), dynamicType);
+ // flatten(Future<int>) = int
+ expect(_flatten(futureIntType), intType);
+ // flatten(Future<Future>) = dynamic
+ expect(_flatten(futureFutureDynamicType), dynamicType);
+ // flatten(Future<Future<int>>) = int
+ expect(_flatten(futureFutureIntType), intType);
+ }
+
+ void test_flatten_unrelated_types() {
+ InterfaceType futureType = _typeProvider.futureType;
+ InterfaceType intType = _typeProvider.intType;
+ InterfaceType stringType = _typeProvider.stringType;
+ // class A extends Future<int> implements Future<String> { ... }
+ ClassElementImpl classA =
+ ElementFactory.classElement('A', futureType.substitute4([intType]));
+ classA.interfaces = <InterfaceType>[
+ futureType.substitute4([stringType])
+ ];
+ // class B extends Future<String> implements Future<int> { ... }
+ ClassElementImpl classB =
+ ElementFactory.classElement('B', futureType.substitute4([stringType]));
+ classB.interfaces = <InterfaceType>[
+ futureType.substitute4([intType])
+ ];
+ // flatten(A) = A and flatten(B) = B, since neither string nor int is more
+ // specific than the other.
+ expect(_flatten(classA.type), classA.type);
+ expect(_flatten(classB.type), classB.type);
+ }
+
+ void test_visitAdjacentStrings() {
+ // "a" "b"
+ Expression node = AstFactory
+ .adjacentStrings([_resolvedString("a"), _resolvedString("b")]);
+ expect(_analyze(node), same(_typeProvider.stringType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitAsExpression() {
+ // class A { ... this as B ... }
+ // class B extends A {}
+ ClassElement superclass = ElementFactory.classElement2("A");
+ InterfaceType superclassType = superclass.type;
+ ClassElement subclass = ElementFactory.classElement("B", superclassType);
+ Expression node = AstFactory.asExpression(
+ AstFactory.thisExpression(), AstFactory.typeName(subclass));
+ expect(_analyze3(node, superclassType), same(subclass.type));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitAssignmentExpression_compound() {
+ // i += 1
+ InterfaceType numType = _typeProvider.numType;
+ SimpleIdentifier identifier = _resolvedVariable(_typeProvider.intType, "i");
+ AssignmentExpression node = AstFactory.assignmentExpression(
+ identifier, TokenType.PLUS_EQ, _resolvedInteger(1));
+ MethodElement plusMethod = getMethod(numType, "+");
+ node.staticElement = plusMethod;
+ expect(_analyze(node), same(numType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitAssignmentExpression_compoundIfNull_differentTypes() {
+ // double d; d ??= 0
+ Expression node = AstFactory.assignmentExpression(
+ _resolvedVariable(_typeProvider.doubleType, 'd'),
+ TokenType.QUESTION_QUESTION_EQ,
+ _resolvedInteger(0));
+ expect(_analyze(node), same(_typeProvider.numType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitAssignmentExpression_compoundIfNull_sameTypes() {
+ // int i; i ??= 0
+ Expression node = AstFactory.assignmentExpression(
+ _resolvedVariable(_typeProvider.intType, 'i'),
+ TokenType.QUESTION_QUESTION_EQ,
+ _resolvedInteger(0));
+ expect(_analyze(node), same(_typeProvider.intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitAssignmentExpression_simple() {
+ // i = 0
+ InterfaceType intType = _typeProvider.intType;
+ Expression node = AstFactory.assignmentExpression(
+ _resolvedVariable(intType, "i"), TokenType.EQ, _resolvedInteger(0));
+ expect(_analyze(node), same(intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitAwaitExpression_flattened() {
+ // await e, where e has type Future<Future<int>>
+ InterfaceType intType = _typeProvider.intType;
+ InterfaceType futureIntType =
+ _typeProvider.futureType.substitute4(<DartType>[intType]);
+ InterfaceType futureFutureIntType =
+ _typeProvider.futureType.substitute4(<DartType>[futureIntType]);
+ Expression node =
+ AstFactory.awaitExpression(_resolvedVariable(futureFutureIntType, 'e'));
+ expect(_analyze(node), same(intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitAwaitExpression_simple() {
+ // await e, where e has type Future<int>
+ InterfaceType intType = _typeProvider.intType;
+ InterfaceType futureIntType =
+ _typeProvider.futureType.substitute4(<DartType>[intType]);
+ Expression node =
+ AstFactory.awaitExpression(_resolvedVariable(futureIntType, 'e'));
+ expect(_analyze(node), same(intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_equals() {
+ // 2 == 3
+ Expression node = AstFactory.binaryExpression(
+ _resolvedInteger(2), TokenType.EQ_EQ, _resolvedInteger(3));
+ expect(_analyze(node), same(_typeProvider.boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_ifNull() {
+ // 1 ?? 1.5
+ Expression node = AstFactory.binaryExpression(
+ _resolvedInteger(1), TokenType.QUESTION_QUESTION, _resolvedDouble(1.5));
+ expect(_analyze(node), same(_typeProvider.numType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_logicalAnd() {
+ // false && true
+ Expression node = AstFactory.binaryExpression(
+ AstFactory.booleanLiteral(false),
+ TokenType.AMPERSAND_AMPERSAND,
+ AstFactory.booleanLiteral(true));
+ expect(_analyze(node), same(_typeProvider.boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_logicalOr() {
+ // false || true
+ Expression node = AstFactory.binaryExpression(
+ AstFactory.booleanLiteral(false),
+ TokenType.BAR_BAR,
+ AstFactory.booleanLiteral(true));
+ expect(_analyze(node), same(_typeProvider.boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_minusID_propagated() {
+ // a - b
+ BinaryExpression node = AstFactory.binaryExpression(
+ _propagatedVariable(_typeProvider.intType, 'a'),
+ TokenType.MINUS,
+ _propagatedVariable(_typeProvider.doubleType, 'b'));
+ node.propagatedElement = getMethod(_typeProvider.numType, "+");
+ _analyze(node);
+ expect(node.propagatedType, same(_typeProvider.doubleType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_notEquals() {
+ // 2 != 3
+ Expression node = AstFactory.binaryExpression(
+ _resolvedInteger(2), TokenType.BANG_EQ, _resolvedInteger(3));
+ expect(_analyze(node), same(_typeProvider.boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_plusID() {
+ // 1 + 2.0
+ BinaryExpression node = AstFactory.binaryExpression(
+ _resolvedInteger(1), TokenType.PLUS, _resolvedDouble(2.0));
+ node.staticElement = getMethod(_typeProvider.numType, "+");
+ expect(_analyze(node), same(_typeProvider.doubleType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_plusII() {
+ // 1 + 2
+ BinaryExpression node = AstFactory.binaryExpression(
+ _resolvedInteger(1), TokenType.PLUS, _resolvedInteger(2));
+ node.staticElement = getMethod(_typeProvider.numType, "+");
+ expect(_analyze(node), same(_typeProvider.intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_plusII_propagated() {
+ // a + b
+ BinaryExpression node = AstFactory.binaryExpression(
+ _propagatedVariable(_typeProvider.intType, 'a'),
+ TokenType.PLUS,
+ _propagatedVariable(_typeProvider.intType, 'b'));
+ node.propagatedElement = getMethod(_typeProvider.numType, "+");
+ _analyze(node);
+ expect(node.propagatedType, same(_typeProvider.intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_slash() {
+ // 2 / 2
+ BinaryExpression node = AstFactory.binaryExpression(
+ _resolvedInteger(2), TokenType.SLASH, _resolvedInteger(2));
+ node.staticElement = getMethod(_typeProvider.numType, "/");
+ expect(_analyze(node), same(_typeProvider.doubleType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_star_notSpecial() {
+ // class A {
+ // A operator *(double value);
+ // }
+ // (a as A) * 2.0
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ InterfaceType typeA = classA.type;
+ MethodElement operator =
+ ElementFactory.methodElement("*", typeA, [_typeProvider.doubleType]);
+ classA.methods = <MethodElement>[operator];
+ BinaryExpression node = AstFactory.binaryExpression(
+ AstFactory.asExpression(
+ AstFactory.identifier3("a"), AstFactory.typeName(classA)),
+ TokenType.PLUS,
+ _resolvedDouble(2.0));
+ node.staticElement = operator;
+ expect(_analyze(node), same(typeA));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBinaryExpression_starID() {
+ // 1 * 2.0
+ BinaryExpression node = AstFactory.binaryExpression(
+ _resolvedInteger(1), TokenType.PLUS, _resolvedDouble(2.0));
+ node.staticElement = getMethod(_typeProvider.numType, "*");
+ expect(_analyze(node), same(_typeProvider.doubleType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBooleanLiteral_false() {
+ // false
+ Expression node = AstFactory.booleanLiteral(false);
+ expect(_analyze(node), same(_typeProvider.boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitBooleanLiteral_true() {
+ // true
+ Expression node = AstFactory.booleanLiteral(true);
+ expect(_analyze(node), same(_typeProvider.boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitCascadeExpression() {
+ // a..length
+ Expression node = AstFactory.cascadeExpression(
+ _resolvedString("a"), [AstFactory.propertyAccess2(null, "length")]);
+ expect(_analyze(node), same(_typeProvider.stringType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitConditionalExpression_differentTypes() {
+ // true ? 1.0 : 0
+ Expression node = AstFactory.conditionalExpression(
+ AstFactory.booleanLiteral(true),
+ _resolvedDouble(1.0),
+ _resolvedInteger(0));
+ expect(_analyze(node), same(_typeProvider.numType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitConditionalExpression_sameTypes() {
+ // true ? 1 : 0
+ Expression node = AstFactory.conditionalExpression(
+ AstFactory.booleanLiteral(true),
+ _resolvedInteger(1),
+ _resolvedInteger(0));
+ expect(_analyze(node), same(_typeProvider.intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitDoubleLiteral() {
+ // 4.33
+ Expression node = AstFactory.doubleLiteral(4.33);
+ expect(_analyze(node), same(_typeProvider.doubleType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_async_block() {
+ // () async {}
+ BlockFunctionBody body = AstFactory.blockFunctionBody2();
+ body.keyword = TokenFactory.tokenFromString('async');
+ FunctionExpression node =
+ _resolvedFunctionExpression(AstFactory.formalParameterList([]), body);
+ DartType resultType = _analyze(node);
+ _assertFunctionType(
+ _typeProvider.futureDynamicType, null, null, null, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_async_expression() {
+ // () async => e, where e has type int
+ InterfaceType intType = _typeProvider.intType;
+ InterfaceType futureIntType =
+ _typeProvider.futureType.substitute4(<DartType>[intType]);
+ Expression expression = _resolvedVariable(intType, 'e');
+ ExpressionFunctionBody body = AstFactory.expressionFunctionBody(expression);
+ body.keyword = TokenFactory.tokenFromString('async');
+ FunctionExpression node =
+ _resolvedFunctionExpression(AstFactory.formalParameterList([]), body);
+ DartType resultType = _analyze(node);
+ _assertFunctionType(futureIntType, null, null, null, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_async_expression_flatten() {
+ // () async => e, where e has type Future<int>
+ InterfaceType intType = _typeProvider.intType;
+ InterfaceType futureIntType =
+ _typeProvider.futureType.substitute4(<DartType>[intType]);
+ Expression expression = _resolvedVariable(futureIntType, 'e');
+ ExpressionFunctionBody body = AstFactory.expressionFunctionBody(expression);
+ body.keyword = TokenFactory.tokenFromString('async');
+ FunctionExpression node =
+ _resolvedFunctionExpression(AstFactory.formalParameterList([]), body);
+ DartType resultType = _analyze(node);
+ _assertFunctionType(futureIntType, null, null, null, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_async_expression_flatten_twice() {
+ // () async => e, where e has type Future<Future<int>>
+ InterfaceType intType = _typeProvider.intType;
+ InterfaceType futureIntType =
+ _typeProvider.futureType.substitute4(<DartType>[intType]);
+ InterfaceType futureFutureIntType =
+ _typeProvider.futureType.substitute4(<DartType>[futureIntType]);
+ Expression expression = _resolvedVariable(futureFutureIntType, 'e');
+ ExpressionFunctionBody body = AstFactory.expressionFunctionBody(expression);
+ body.keyword = TokenFactory.tokenFromString('async');
+ FunctionExpression node =
+ _resolvedFunctionExpression(AstFactory.formalParameterList([]), body);
+ DartType resultType = _analyze(node);
+ _assertFunctionType(futureIntType, null, null, null, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_generator_async() {
+ // () async* {}
+ BlockFunctionBody body = AstFactory.blockFunctionBody2();
+ body.keyword = TokenFactory.tokenFromString('async');
+ body.star = TokenFactory.tokenFromType(TokenType.STAR);
+ FunctionExpression node =
+ _resolvedFunctionExpression(AstFactory.formalParameterList([]), body);
+ DartType resultType = _analyze(node);
+ _assertFunctionType(
+ _typeProvider.streamDynamicType, null, null, null, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_generator_sync() {
+ // () sync* {}
+ BlockFunctionBody body = AstFactory.blockFunctionBody2();
+ body.keyword = TokenFactory.tokenFromString('sync');
+ body.star = TokenFactory.tokenFromType(TokenType.STAR);
+ FunctionExpression node =
+ _resolvedFunctionExpression(AstFactory.formalParameterList([]), body);
+ DartType resultType = _analyze(node);
+ _assertFunctionType(
+ _typeProvider.iterableDynamicType, null, null, null, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_named_block() {
+ // ({p1 : 0, p2 : 0}) {}
+ DartType dynamicType = _typeProvider.dynamicType;
+ FormalParameter p1 = AstFactory.namedFormalParameter(
+ AstFactory.simpleFormalParameter3("p1"), _resolvedInteger(0));
+ _setType(p1, dynamicType);
+ FormalParameter p2 = AstFactory.namedFormalParameter(
+ AstFactory.simpleFormalParameter3("p2"), _resolvedInteger(0));
+ _setType(p2, dynamicType);
+ FunctionExpression node = _resolvedFunctionExpression(
+ AstFactory.formalParameterList([p1, p2]),
+ AstFactory.blockFunctionBody2());
+ _analyze5(p1);
+ _analyze5(p2);
+ DartType resultType = _analyze(node);
+ Map<String, DartType> expectedNamedTypes = new HashMap<String, DartType>();
+ expectedNamedTypes["p1"] = dynamicType;
+ expectedNamedTypes["p2"] = dynamicType;
+ _assertFunctionType(
+ dynamicType, null, null, expectedNamedTypes, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_named_expression() {
+ // ({p : 0}) -> 0;
+ DartType dynamicType = _typeProvider.dynamicType;
+ FormalParameter p = AstFactory.namedFormalParameter(
+ AstFactory.simpleFormalParameter3("p"), _resolvedInteger(0));
+ _setType(p, dynamicType);
+ FunctionExpression node = _resolvedFunctionExpression(
+ AstFactory.formalParameterList([p]),
+ AstFactory.expressionFunctionBody(_resolvedInteger(0)));
+ _analyze5(p);
+ DartType resultType = _analyze(node);
+ Map<String, DartType> expectedNamedTypes = new HashMap<String, DartType>();
+ expectedNamedTypes["p"] = dynamicType;
+ _assertFunctionType(
+ _typeProvider.intType, null, null, expectedNamedTypes, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_normal_block() {
+ // (p1, p2) {}
+ DartType dynamicType = _typeProvider.dynamicType;
+ FormalParameter p1 = AstFactory.simpleFormalParameter3("p1");
+ _setType(p1, dynamicType);
+ FormalParameter p2 = AstFactory.simpleFormalParameter3("p2");
+ _setType(p2, dynamicType);
+ FunctionExpression node = _resolvedFunctionExpression(
+ AstFactory.formalParameterList([p1, p2]),
+ AstFactory.blockFunctionBody2());
+ _analyze5(p1);
+ _analyze5(p2);
+ DartType resultType = _analyze(node);
+ _assertFunctionType(dynamicType, <DartType>[dynamicType, dynamicType], null,
+ null, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_normal_expression() {
+ // (p1, p2) -> 0
+ DartType dynamicType = _typeProvider.dynamicType;
+ FormalParameter p = AstFactory.simpleFormalParameter3("p");
+ _setType(p, dynamicType);
+ FunctionExpression node = _resolvedFunctionExpression(
+ AstFactory.formalParameterList([p]),
+ AstFactory.expressionFunctionBody(_resolvedInteger(0)));
+ _analyze5(p);
+ DartType resultType = _analyze(node);
+ _assertFunctionType(
+ _typeProvider.intType, <DartType>[dynamicType], null, null, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_normalAndNamed_block() {
+ // (p1, {p2 : 0}) {}
+ DartType dynamicType = _typeProvider.dynamicType;
+ FormalParameter p1 = AstFactory.simpleFormalParameter3("p1");
+ _setType(p1, dynamicType);
+ FormalParameter p2 = AstFactory.namedFormalParameter(
+ AstFactory.simpleFormalParameter3("p2"), _resolvedInteger(0));
+ _setType(p2, dynamicType);
+ FunctionExpression node = _resolvedFunctionExpression(
+ AstFactory.formalParameterList([p1, p2]),
+ AstFactory.blockFunctionBody2());
+ _analyze5(p2);
+ DartType resultType = _analyze(node);
+ Map<String, DartType> expectedNamedTypes = new HashMap<String, DartType>();
+ expectedNamedTypes["p2"] = dynamicType;
+ _assertFunctionType(dynamicType, <DartType>[dynamicType], null,
+ expectedNamedTypes, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_normalAndNamed_expression() {
+ // (p1, {p2 : 0}) -> 0
+ DartType dynamicType = _typeProvider.dynamicType;
+ FormalParameter p1 = AstFactory.simpleFormalParameter3("p1");
+ _setType(p1, dynamicType);
+ FormalParameter p2 = AstFactory.namedFormalParameter(
+ AstFactory.simpleFormalParameter3("p2"), _resolvedInteger(0));
+ _setType(p2, dynamicType);
+ FunctionExpression node = _resolvedFunctionExpression(
+ AstFactory.formalParameterList([p1, p2]),
+ AstFactory.expressionFunctionBody(_resolvedInteger(0)));
+ _analyze5(p2);
+ DartType resultType = _analyze(node);
+ Map<String, DartType> expectedNamedTypes = new HashMap<String, DartType>();
+ expectedNamedTypes["p2"] = dynamicType;
+ _assertFunctionType(_typeProvider.intType, <DartType>[dynamicType], null,
+ expectedNamedTypes, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_normalAndPositional_block() {
+ // (p1, [p2 = 0]) {}
+ DartType dynamicType = _typeProvider.dynamicType;
+ FormalParameter p1 = AstFactory.simpleFormalParameter3("p1");
+ _setType(p1, dynamicType);
+ FormalParameter p2 = AstFactory.positionalFormalParameter(
+ AstFactory.simpleFormalParameter3("p2"), _resolvedInteger(0));
+ _setType(p2, dynamicType);
+ FunctionExpression node = _resolvedFunctionExpression(
+ AstFactory.formalParameterList([p1, p2]),
+ AstFactory.blockFunctionBody2());
+ _analyze5(p1);
+ _analyze5(p2);
+ DartType resultType = _analyze(node);
+ _assertFunctionType(dynamicType, <DartType>[dynamicType],
+ <DartType>[dynamicType], null, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_normalAndPositional_expression() {
+ // (p1, [p2 = 0]) -> 0
+ DartType dynamicType = _typeProvider.dynamicType;
+ FormalParameter p1 = AstFactory.simpleFormalParameter3("p1");
+ _setType(p1, dynamicType);
+ FormalParameter p2 = AstFactory.positionalFormalParameter(
+ AstFactory.simpleFormalParameter3("p2"), _resolvedInteger(0));
+ _setType(p2, dynamicType);
+ FunctionExpression node = _resolvedFunctionExpression(
+ AstFactory.formalParameterList([p1, p2]),
+ AstFactory.expressionFunctionBody(_resolvedInteger(0)));
+ _analyze5(p1);
+ _analyze5(p2);
+ DartType resultType = _analyze(node);
+ _assertFunctionType(_typeProvider.intType, <DartType>[dynamicType],
+ <DartType>[dynamicType], null, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_positional_block() {
+ // ([p1 = 0, p2 = 0]) {}
+ DartType dynamicType = _typeProvider.dynamicType;
+ FormalParameter p1 = AstFactory.positionalFormalParameter(
+ AstFactory.simpleFormalParameter3("p1"), _resolvedInteger(0));
+ _setType(p1, dynamicType);
+ FormalParameter p2 = AstFactory.positionalFormalParameter(
+ AstFactory.simpleFormalParameter3("p2"), _resolvedInteger(0));
+ _setType(p2, dynamicType);
+ FunctionExpression node = _resolvedFunctionExpression(
+ AstFactory.formalParameterList([p1, p2]),
+ AstFactory.blockFunctionBody2());
+ _analyze5(p1);
+ _analyze5(p2);
+ DartType resultType = _analyze(node);
+ _assertFunctionType(dynamicType, null, <DartType>[dynamicType, dynamicType],
+ null, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionExpression_positional_expression() {
+ // ([p1 = 0, p2 = 0]) -> 0
+ DartType dynamicType = _typeProvider.dynamicType;
+ FormalParameter p = AstFactory.positionalFormalParameter(
+ AstFactory.simpleFormalParameter3("p"), _resolvedInteger(0));
+ _setType(p, dynamicType);
+ FunctionExpression node = _resolvedFunctionExpression(
+ AstFactory.formalParameterList([p]),
+ AstFactory.expressionFunctionBody(_resolvedInteger(0)));
+ _analyze5(p);
+ DartType resultType = _analyze(node);
+ _assertFunctionType(
+ _typeProvider.intType, null, <DartType>[dynamicType], null, resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitIndexExpression_getter() {
+ // List a;
+ // a[2]
+ InterfaceType listType = _typeProvider.listType;
+ SimpleIdentifier identifier = _resolvedVariable(listType, "a");
+ IndexExpression node =
+ AstFactory.indexExpression(identifier, _resolvedInteger(2));
+ MethodElement indexMethod = listType.element.methods[0];
+ node.staticElement = indexMethod;
+ expect(_analyze(node), same(listType.typeArguments[0]));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitIndexExpression_setter() {
+ // List a;
+ // a[2] = 0
+ InterfaceType listType = _typeProvider.listType;
+ SimpleIdentifier identifier = _resolvedVariable(listType, "a");
+ IndexExpression node =
+ AstFactory.indexExpression(identifier, _resolvedInteger(2));
+ MethodElement indexMethod = listType.element.methods[1];
+ node.staticElement = indexMethod;
+ AstFactory.assignmentExpression(node, TokenType.EQ, AstFactory.integer(0));
+ expect(_analyze(node), same(listType.typeArguments[0]));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitIndexExpression_typeParameters() {
+ // List<int> list = ...
+ // list[0]
+ InterfaceType intType = _typeProvider.intType;
+ InterfaceType listType = _typeProvider.listType;
+ // (int) -> E
+ MethodElement methodElement = getMethod(listType, "[]");
+ // "list" has type List<int>
+ SimpleIdentifier identifier = AstFactory.identifier3("list");
+ InterfaceType listOfIntType = listType.substitute4(<DartType>[intType]);
+ identifier.staticType = listOfIntType;
+ // list[0] has MethodElement element (int) -> E
+ IndexExpression indexExpression =
+ AstFactory.indexExpression(identifier, AstFactory.integer(0));
+ MethodElement indexMethod = MethodMember.from(methodElement, listOfIntType);
+ indexExpression.staticElement = indexMethod;
+ // analyze and assert result of the index expression
+ expect(_analyze(indexExpression), same(intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitIndexExpression_typeParameters_inSetterContext() {
+ // List<int> list = ...
+ // list[0] = 0;
+ InterfaceType intType = _typeProvider.intType;
+ InterfaceType listType = _typeProvider.listType;
+ // (int, E) -> void
+ MethodElement methodElement = getMethod(listType, "[]=");
+ // "list" has type List<int>
+ SimpleIdentifier identifier = AstFactory.identifier3("list");
+ InterfaceType listOfIntType = listType.substitute4(<DartType>[intType]);
+ identifier.staticType = listOfIntType;
+ // list[0] has MethodElement element (int) -> E
+ IndexExpression indexExpression =
+ AstFactory.indexExpression(identifier, AstFactory.integer(0));
+ MethodElement indexMethod = MethodMember.from(methodElement, listOfIntType);
+ indexExpression.staticElement = indexMethod;
+ // list[0] should be in a setter context
+ AstFactory.assignmentExpression(
+ indexExpression, TokenType.EQ, AstFactory.integer(0));
+ // analyze and assert result of the index expression
+ expect(_analyze(indexExpression), same(intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitInstanceCreationExpression_named() {
+ // new C.m()
+ ClassElementImpl classElement = ElementFactory.classElement2("C");
+ String constructorName = "m";
+ ConstructorElementImpl constructor =
+ ElementFactory.constructorElement2(classElement, constructorName);
+ constructor.returnType = classElement.type;
+ FunctionTypeImpl constructorType = new FunctionTypeImpl(constructor);
+ constructor.type = constructorType;
+ classElement.constructors = <ConstructorElement>[constructor];
+ InstanceCreationExpression node = AstFactory.instanceCreationExpression2(
+ null,
+ AstFactory.typeName(classElement),
+ [AstFactory.identifier3(constructorName)]);
+ node.staticElement = constructor;
+ expect(_analyze(node), same(classElement.type));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitInstanceCreationExpression_typeParameters() {
+ // new C<I>()
+ ClassElementImpl elementC = ElementFactory.classElement2("C", ["E"]);
+ ClassElementImpl elementI = ElementFactory.classElement2("I");
+ ConstructorElementImpl constructor =
+ ElementFactory.constructorElement2(elementC, null);
+ elementC.constructors = <ConstructorElement>[constructor];
+ constructor.returnType = elementC.type;
+ FunctionTypeImpl constructorType = new FunctionTypeImpl(constructor);
+ constructor.type = constructorType;
+ TypeName typeName =
+ AstFactory.typeName(elementC, [AstFactory.typeName(elementI)]);
+ typeName.type = elementC.type.substitute4(<DartType>[elementI.type]);
+ InstanceCreationExpression node =
+ AstFactory.instanceCreationExpression2(null, typeName);
+ node.staticElement = constructor;
+ InterfaceType interfaceType = _analyze(node) as InterfaceType;
+ List<DartType> typeArgs = interfaceType.typeArguments;
+ expect(typeArgs.length, 1);
+ expect(typeArgs[0], elementI.type);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitInstanceCreationExpression_unnamed() {
+ // new C()
+ ClassElementImpl classElement = ElementFactory.classElement2("C");
+ ConstructorElementImpl constructor =
+ ElementFactory.constructorElement2(classElement, null);
+ constructor.returnType = classElement.type;
+ FunctionTypeImpl constructorType = new FunctionTypeImpl(constructor);
+ constructor.type = constructorType;
+ classElement.constructors = <ConstructorElement>[constructor];
+ InstanceCreationExpression node = AstFactory.instanceCreationExpression2(
+ null, AstFactory.typeName(classElement));
+ node.staticElement = constructor;
+ expect(_analyze(node), same(classElement.type));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitIntegerLiteral() {
+ // 42
+ Expression node = _resolvedInteger(42);
+ expect(_analyze(node), same(_typeProvider.intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitIsExpression_negated() {
+ // a is! String
+ Expression node = AstFactory.isExpression(
+ _resolvedString("a"), true, AstFactory.typeName4("String"));
+ expect(_analyze(node), same(_typeProvider.boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitIsExpression_notNegated() {
+ // a is String
+ Expression node = AstFactory.isExpression(
+ _resolvedString("a"), false, AstFactory.typeName4("String"));
+ expect(_analyze(node), same(_typeProvider.boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitListLiteral_empty() {
+ // []
+ Expression node = AstFactory.listLiteral();
+ DartType resultType = _analyze(node);
+ _assertType2(
+ _typeProvider.listType
+ .substitute4(<DartType>[_typeProvider.dynamicType]),
+ resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitListLiteral_nonEmpty() {
+ // [0]
+ Expression node = AstFactory.listLiteral([_resolvedInteger(0)]);
+ DartType resultType = _analyze(node);
+ _assertType2(
+ _typeProvider.listType
+ .substitute4(<DartType>[_typeProvider.dynamicType]),
+ resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitMapLiteral_empty() {
+ // {}
+ Expression node = AstFactory.mapLiteral2();
+ DartType resultType = _analyze(node);
+ _assertType2(
+ _typeProvider.mapType.substitute4(
+ <DartType>[_typeProvider.dynamicType, _typeProvider.dynamicType]),
+ resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitMapLiteral_nonEmpty() {
+ // {"k" : 0}
+ Expression node = AstFactory
+ .mapLiteral2([AstFactory.mapLiteralEntry("k", _resolvedInteger(0))]);
+ DartType resultType = _analyze(node);
+ _assertType2(
+ _typeProvider.mapType.substitute4(
+ <DartType>[_typeProvider.dynamicType, _typeProvider.dynamicType]),
+ resultType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitMethodInvocation_then() {
+ // then()
+ Expression node = AstFactory.methodInvocation(null, "then");
+ _analyze(node);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitNamedExpression() {
+ // n: a
+ Expression node = AstFactory.namedExpression2("n", _resolvedString("a"));
+ expect(_analyze(node), same(_typeProvider.stringType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitNullLiteral() {
+ // null
+ Expression node = AstFactory.nullLiteral();
+ expect(_analyze(node), same(_typeProvider.bottomType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitParenthesizedExpression() {
+ // (0)
+ Expression node = AstFactory.parenthesizedExpression(_resolvedInteger(0));
+ expect(_analyze(node), same(_typeProvider.intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPostfixExpression_minusMinus() {
+ // 0--
+ PostfixExpression node = AstFactory.postfixExpression(
+ _resolvedInteger(0), TokenType.MINUS_MINUS);
+ expect(_analyze(node), same(_typeProvider.intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPostfixExpression_plusPlus() {
+ // 0++
+ PostfixExpression node =
+ AstFactory.postfixExpression(_resolvedInteger(0), TokenType.PLUS_PLUS);
+ expect(_analyze(node), same(_typeProvider.intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPrefixedIdentifier_getter() {
+ DartType boolType = _typeProvider.boolType;
+ PropertyAccessorElementImpl getter =
+ ElementFactory.getterElement("b", false, boolType);
+ PrefixedIdentifier node = AstFactory.identifier5("a", "b");
+ node.identifier.staticElement = getter;
+ expect(_analyze(node), same(boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPrefixedIdentifier_setter() {
+ DartType boolType = _typeProvider.boolType;
+ FieldElementImpl field =
+ ElementFactory.fieldElement("b", false, false, false, boolType);
+ PropertyAccessorElement setter = field.setter;
+ PrefixedIdentifier node = AstFactory.identifier5("a", "b");
+ node.identifier.staticElement = setter;
+ expect(_analyze(node), same(boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPrefixedIdentifier_variable() {
+ VariableElementImpl variable = ElementFactory.localVariableElement2("b");
+ variable.type = _typeProvider.boolType;
+ PrefixedIdentifier node = AstFactory.identifier5("a", "b");
+ node.identifier.staticElement = variable;
+ expect(_analyze(node), same(_typeProvider.boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPrefixExpression_bang() {
+ // !0
+ PrefixExpression node =
+ AstFactory.prefixExpression(TokenType.BANG, _resolvedInteger(0));
+ expect(_analyze(node), same(_typeProvider.boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPrefixExpression_minus() {
+ // -0
+ PrefixExpression node =
+ AstFactory.prefixExpression(TokenType.MINUS, _resolvedInteger(0));
+ MethodElement minusMethod = getMethod(_typeProvider.numType, "-");
+ node.staticElement = minusMethod;
+ expect(_analyze(node), same(_typeProvider.numType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPrefixExpression_minusMinus() {
+ // --0
+ PrefixExpression node =
+ AstFactory.prefixExpression(TokenType.MINUS_MINUS, _resolvedInteger(0));
+ MethodElement minusMethod = getMethod(_typeProvider.numType, "-");
+ node.staticElement = minusMethod;
+ expect(_analyze(node), same(_typeProvider.intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPrefixExpression_not() {
+ // !true
+ Expression node = AstFactory.prefixExpression(
+ TokenType.BANG, AstFactory.booleanLiteral(true));
+ expect(_analyze(node), same(_typeProvider.boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPrefixExpression_plusPlus() {
+ // ++0
+ PrefixExpression node =
+ AstFactory.prefixExpression(TokenType.PLUS_PLUS, _resolvedInteger(0));
+ MethodElement plusMethod = getMethod(_typeProvider.numType, "+");
+ node.staticElement = plusMethod;
+ expect(_analyze(node), same(_typeProvider.intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPrefixExpression_tilde() {
+ // ~0
+ PrefixExpression node =
+ AstFactory.prefixExpression(TokenType.TILDE, _resolvedInteger(0));
+ MethodElement tildeMethod = getMethod(_typeProvider.intType, "~");
+ node.staticElement = tildeMethod;
+ expect(_analyze(node), same(_typeProvider.intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPropertyAccess_propagated_getter() {
+ DartType boolType = _typeProvider.boolType;
+ PropertyAccessorElementImpl getter =
+ ElementFactory.getterElement("b", false, boolType);
+ PropertyAccess node =
+ AstFactory.propertyAccess2(AstFactory.identifier3("a"), "b");
+ node.propertyName.propagatedElement = getter;
+ expect(_analyze2(node, false), same(boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPropertyAccess_propagated_setter() {
+ DartType boolType = _typeProvider.boolType;
+ FieldElementImpl field =
+ ElementFactory.fieldElement("b", false, false, false, boolType);
+ PropertyAccessorElement setter = field.setter;
+ PropertyAccess node =
+ AstFactory.propertyAccess2(AstFactory.identifier3("a"), "b");
+ node.propertyName.propagatedElement = setter;
+ expect(_analyze2(node, false), same(boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPropertyAccess_static_getter() {
+ DartType boolType = _typeProvider.boolType;
+ PropertyAccessorElementImpl getter =
+ ElementFactory.getterElement("b", false, boolType);
+ PropertyAccess node =
+ AstFactory.propertyAccess2(AstFactory.identifier3("a"), "b");
+ node.propertyName.staticElement = getter;
+ expect(_analyze(node), same(boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitPropertyAccess_static_setter() {
+ DartType boolType = _typeProvider.boolType;
+ FieldElementImpl field =
+ ElementFactory.fieldElement("b", false, false, false, boolType);
+ PropertyAccessorElement setter = field.setter;
+ PropertyAccess node =
+ AstFactory.propertyAccess2(AstFactory.identifier3("a"), "b");
+ node.propertyName.staticElement = setter;
+ expect(_analyze(node), same(boolType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitSimpleIdentifier_dynamic() {
+ // "dynamic"
+ SimpleIdentifier identifier = AstFactory.identifier3('dynamic');
+ DynamicElementImpl element = DynamicElementImpl.instance;
+ identifier.staticElement = element;
+ identifier.staticType = _typeProvider.typeType;
+ expect(_analyze(identifier), same(_typeProvider.typeType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitSimpleStringLiteral() {
+ // "a"
+ Expression node = _resolvedString("a");
+ expect(_analyze(node), same(_typeProvider.stringType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitStringInterpolation() {
+ // "a${'b'}c"
+ Expression node = AstFactory.string([
+ AstFactory.interpolationString("a", "a"),
+ AstFactory.interpolationExpression(_resolvedString("b")),
+ AstFactory.interpolationString("c", "c")
+ ]);
+ expect(_analyze(node), same(_typeProvider.stringType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitSuperExpression() {
+ // super
+ InterfaceType superType = ElementFactory.classElement2("A").type;
+ InterfaceType thisType = ElementFactory.classElement("B", superType).type;
+ Expression node = AstFactory.superExpression();
+ expect(_analyze3(node, thisType), same(thisType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitSymbolLiteral() {
+ expect(_analyze(AstFactory.symbolLiteral(["a"])),
+ same(_typeProvider.symbolType));
+ }
+
+ void test_visitThisExpression() {
+ // this
+ InterfaceType thisType = ElementFactory
+ .classElement("B", ElementFactory.classElement2("A").type)
+ .type;
+ Expression node = AstFactory.thisExpression();
+ expect(_analyze3(node, thisType), same(thisType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitThrowExpression_withoutValue() {
+ // throw
+ Expression node = AstFactory.throwExpression();
+ expect(_analyze(node), same(_typeProvider.bottomType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitThrowExpression_withValue() {
+ // throw 0
+ Expression node = AstFactory.throwExpression2(_resolvedInteger(0));
+ expect(_analyze(node), same(_typeProvider.bottomType));
+ _listener.assertNoErrors();
+ }
+
+ /**
+ * Return the type associated with the given expression after the static type analyzer has
+ * computed a type for it.
+ *
+ * @param node the expression with which the type is associated
+ * @return the type associated with the expression
+ */
+ DartType _analyze(Expression node) => _analyze4(node, null, true);
+
+ /**
+ * Return the type associated with the given expression after the static or propagated type
+ * analyzer has computed a type for it.
+ *
+ * @param node the expression with which the type is associated
+ * @param useStaticType `true` if the static type is being requested, and `false` if
+ * the propagated type is being requested
+ * @return the type associated with the expression
+ */
+ DartType _analyze2(Expression node, bool useStaticType) =>
+ _analyze4(node, null, useStaticType);
+
+ /**
+ * Return the type associated with the given expression after the static type analyzer has
+ * computed a type for it.
+ *
+ * @param node the expression with which the type is associated
+ * @param thisType the type of 'this'
+ * @return the type associated with the expression
+ */
+ DartType _analyze3(Expression node, InterfaceType thisType) =>
+ _analyze4(node, thisType, true);
+
+ /**
+ * Return the type associated with the given expression after the static type analyzer has
+ * computed a type for it.
+ *
+ * @param node the expression with which the type is associated
+ * @param thisType the type of 'this'
+ * @param useStaticType `true` if the static type is being requested, and `false` if
+ * the propagated type is being requested
+ * @return the type associated with the expression
+ */
+ DartType _analyze4(
+ Expression node, InterfaceType thisType, bool useStaticType) {
+ try {
+ _analyzer.thisType = thisType;
+ } catch (exception) {
+ throw new IllegalArgumentException(
+ "Could not set type of 'this'", exception);
+ }
+ node.accept(_analyzer);
+ if (useStaticType) {
+ return node.staticType;
+ } else {
+ return node.propagatedType;
+ }
+ }
+
+ /**
+ * Return the type associated with the given parameter after the static type analyzer has computed
+ * a type for it.
+ *
+ * @param node the parameter with which the type is associated
+ * @return the type associated with the parameter
+ */
+ DartType _analyze5(FormalParameter node) {
+ node.accept(_analyzer);
+ return (node.identifier.staticElement as ParameterElement).type;
+ }
+
+ /**
+ * Assert that the actual type is a function type with the expected characteristics.
+ *
+ * @param expectedReturnType the expected return type of the function
+ * @param expectedNormalTypes the expected types of the normal parameters
+ * @param expectedOptionalTypes the expected types of the optional parameters
+ * @param expectedNamedTypes the expected types of the named parameters
+ * @param actualType the type being tested
+ */
+ void _assertFunctionType(
+ DartType expectedReturnType,
+ List<DartType> expectedNormalTypes,
+ List<DartType> expectedOptionalTypes,
+ Map<String, DartType> expectedNamedTypes,
+ DartType actualType) {
+ EngineTestCase.assertInstanceOf(
+ (obj) => obj is FunctionType, FunctionType, actualType);
+ FunctionType functionType = actualType as FunctionType;
+ List<DartType> normalTypes = functionType.normalParameterTypes;
+ if (expectedNormalTypes == null) {
+ expect(normalTypes, hasLength(0));
+ } else {
+ int expectedCount = expectedNormalTypes.length;
+ expect(normalTypes, hasLength(expectedCount));
+ for (int i = 0; i < expectedCount; i++) {
+ expect(normalTypes[i], same(expectedNormalTypes[i]));
+ }
+ }
+ List<DartType> optionalTypes = functionType.optionalParameterTypes;
+ if (expectedOptionalTypes == null) {
+ expect(optionalTypes, hasLength(0));
+ } else {
+ int expectedCount = expectedOptionalTypes.length;
+ expect(optionalTypes, hasLength(expectedCount));
+ for (int i = 0; i < expectedCount; i++) {
+ expect(optionalTypes[i], same(expectedOptionalTypes[i]));
+ }
+ }
+ Map<String, DartType> namedTypes = functionType.namedParameterTypes;
+ if (expectedNamedTypes == null) {
+ expect(namedTypes, hasLength(0));
+ } else {
+ expect(namedTypes, hasLength(expectedNamedTypes.length));
+ expectedNamedTypes.forEach((String name, DartType type) {
+ expect(namedTypes[name], same(type));
+ });
+ }
+ expect(functionType.returnType, equals(expectedReturnType));
+ }
+
+ void _assertType(
+ InterfaceTypeImpl expectedType, InterfaceTypeImpl actualType) {
+ expect(actualType.displayName, expectedType.displayName);
+ expect(actualType.element, expectedType.element);
+ List<DartType> expectedArguments = expectedType.typeArguments;
+ int length = expectedArguments.length;
+ List<DartType> actualArguments = actualType.typeArguments;
+ expect(actualArguments, hasLength(length));
+ for (int i = 0; i < length; i++) {
+ _assertType2(expectedArguments[i], actualArguments[i]);
+ }
+ }
+
+ void _assertType2(DartType expectedType, DartType actualType) {
+ if (expectedType is InterfaceTypeImpl) {
+ EngineTestCase.assertInstanceOf(
+ (obj) => obj is InterfaceTypeImpl, InterfaceTypeImpl, actualType);
+ _assertType(expectedType, actualType as InterfaceTypeImpl);
+ }
+ // TODO(brianwilkerson) Compare other kinds of types then make this a shared
+ // utility method.
+ }
+
+ /**
+ * Create the analyzer used by the tests.
+ *
+ * @return the analyzer to be used by the tests
+ */
+ StaticTypeAnalyzer _createAnalyzer() {
+ InternalAnalysisContext context = AnalysisContextFactory.contextWithCore();
+ FileBasedSource source =
+ new FileBasedSource(FileUtilities2.createFile("/lib.dart"));
+ CompilationUnitElementImpl definingCompilationUnit =
+ new CompilationUnitElementImpl("lib.dart");
+ definingCompilationUnit.librarySource =
+ definingCompilationUnit.source = source;
+ LibraryElementImpl definingLibrary =
+ new LibraryElementImpl.forNode(context, null);
+ definingLibrary.definingCompilationUnit = definingCompilationUnit;
+ Library library = new Library(context, _listener, source);
+ library.libraryElement = definingLibrary;
+ _visitor = new ResolverVisitor(
+ library.libraryElement, source, _typeProvider, library.errorListener,
+ nameScope: library.libraryScope,
+ inheritanceManager: library.inheritanceManager);
+ _visitor.overrideManager.enterScope();
+ try {
+ return _visitor.typeAnalyzer;
+ } catch (exception) {
+ throw new IllegalArgumentException(
+ "Could not create analyzer", exception);
+ }
+ }
+
+ DartType _flatten(DartType type) =>
+ StaticTypeAnalyzer.flattenFutures(_typeProvider, type);
+
+ /**
+ * Return a simple identifier that has been resolved to a variable element with the given type.
+ *
+ * @param type the type of the variable being represented
+ * @param variableName the name of the variable
+ * @return a simple identifier that has been resolved to a variable element with the given type
+ */
+ SimpleIdentifier _propagatedVariable(
+ InterfaceType type, String variableName) {
+ SimpleIdentifier identifier = AstFactory.identifier3(variableName);
+ VariableElementImpl element =
+ ElementFactory.localVariableElement(identifier);
+ element.type = type;
+ identifier.staticType = _typeProvider.dynamicType;
+ identifier.propagatedElement = element;
+ identifier.propagatedType = type;
+ return identifier;
+ }
+
+ /**
+ * Return an integer literal that has been resolved to the correct type.
+ *
+ * @param value the value of the literal
+ * @return an integer literal that has been resolved to the correct type
+ */
+ DoubleLiteral _resolvedDouble(double value) {
+ DoubleLiteral literal = AstFactory.doubleLiteral(value);
+ literal.staticType = _typeProvider.doubleType;
+ return literal;
+ }
+
+ /**
+ * Create a function expression that has an element associated with it, where the element has an
+ * incomplete type associated with it (just like the one
+ * [ElementBuilder.visitFunctionExpression] would have built if we had
+ * run it).
+ *
+ * @param parameters the parameters to the function
+ * @param body the body of the function
+ * @return a resolved function expression
+ */
+ FunctionExpression _resolvedFunctionExpression(
+ FormalParameterList parameters, FunctionBody body) {
+ List<ParameterElement> parameterElements = new List<ParameterElement>();
+ for (FormalParameter parameter in parameters.parameters) {
+ ParameterElementImpl element =
+ new ParameterElementImpl.forNode(parameter.identifier);
+ element.parameterKind = parameter.kind;
+ element.type = _typeProvider.dynamicType;
+ parameter.identifier.staticElement = element;
+ parameterElements.add(element);
+ }
+ FunctionExpression node = AstFactory.functionExpression2(parameters, body);
+ FunctionElementImpl element = new FunctionElementImpl.forNode(null);
+ element.parameters = parameterElements;
+ element.type = new FunctionTypeImpl(element);
+ node.element = element;
+ return node;
+ }
+
+ /**
+ * Return an integer literal that has been resolved to the correct type.
+ *
+ * @param value the value of the literal
+ * @return an integer literal that has been resolved to the correct type
+ */
+ IntegerLiteral _resolvedInteger(int value) {
+ IntegerLiteral literal = AstFactory.integer(value);
+ literal.staticType = _typeProvider.intType;
+ return literal;
+ }
+
+ /**
+ * Return a string literal that has been resolved to the correct type.
+ *
+ * @param value the value of the literal
+ * @return a string literal that has been resolved to the correct type
+ */
+ SimpleStringLiteral _resolvedString(String value) {
+ SimpleStringLiteral string = AstFactory.string2(value);
+ string.staticType = _typeProvider.stringType;
+ return string;
+ }
+
+ /**
+ * Return a simple identifier that has been resolved to a variable element with the given type.
+ *
+ * @param type the type of the variable being represented
+ * @param variableName the name of the variable
+ * @return a simple identifier that has been resolved to a variable element with the given type
+ */
+ SimpleIdentifier _resolvedVariable(InterfaceType type, String variableName) {
+ SimpleIdentifier identifier = AstFactory.identifier3(variableName);
+ VariableElementImpl element =
+ ElementFactory.localVariableElement(identifier);
+ element.type = type;
+ identifier.staticElement = element;
+ identifier.staticType = type;
+ return identifier;
+ }
+
+ /**
+ * Set the type of the given parameter to the given type.
+ *
+ * @param parameter the parameter whose type is to be set
+ * @param type the new type of the given parameter
+ */
+ void _setType(FormalParameter parameter, DartType type) {
+ SimpleIdentifier identifier = parameter.identifier;
+ Element element = identifier.staticElement;
+ if (element is! ParameterElement) {
+ element = new ParameterElementImpl.forNode(identifier);
+ identifier.staticElement = element;
+ }
+ (element as ParameterElementImpl).type = type;
+ }
+}
+
+/**
+ * Instances of the class `StaticTypeVerifier` verify that all of the nodes in an AST
+ * structure that should have a static type associated with them do have a static type.
+ */
+class StaticTypeVerifier extends GeneralizingAstVisitor<Object> {
+ /**
+ * A list containing all of the AST Expression nodes that were not resolved.
+ */
+ List<Expression> _unresolvedExpressions = new List<Expression>();
+
+ /**
+ * A list containing all of the AST Expression nodes for which a propagated type was computed but
+ * where that type was not more specific than the static type.
+ */
+ List<Expression> _invalidlyPropagatedExpressions = new List<Expression>();
+
+ /**
+ * A list containing all of the AST TypeName nodes that were not resolved.
+ */
+ List<TypeName> _unresolvedTypes = new List<TypeName>();
+
+ /**
+ * Counter for the number of Expression nodes visited that are resolved.
+ */
+ int _resolvedExpressionCount = 0;
+
+ /**
+ * Counter for the number of Expression nodes visited that have propagated type information.
+ */
+ int _propagatedExpressionCount = 0;
+
+ /**
+ * Counter for the number of TypeName nodes visited that are resolved.
+ */
+ int _resolvedTypeCount = 0;
+
+ /**
+ * Assert that all of the visited nodes have a static type associated with them.
+ */
+ void assertResolved() {
+ if (!_unresolvedExpressions.isEmpty || !_unresolvedTypes.isEmpty) {
+ StringBuffer buffer = new StringBuffer();
+ int unresolvedTypeCount = _unresolvedTypes.length;
+ if (unresolvedTypeCount > 0) {
+ buffer.write("Failed to resolve ");
+ buffer.write(unresolvedTypeCount);
+ buffer.write(" of ");
+ buffer.write(_resolvedTypeCount + unresolvedTypeCount);
+ buffer.writeln(" type names:");
+ for (TypeName identifier in _unresolvedTypes) {
+ buffer.write(" ");
+ buffer.write(identifier.toString());
+ buffer.write(" (");
+ buffer.write(_getFileName(identifier));
+ buffer.write(" : ");
+ buffer.write(identifier.offset);
+ buffer.writeln(")");
+ }
+ }
+ int unresolvedExpressionCount = _unresolvedExpressions.length;
+ if (unresolvedExpressionCount > 0) {
+ buffer.writeln("Failed to resolve ");
+ buffer.write(unresolvedExpressionCount);
+ buffer.write(" of ");
+ buffer.write(_resolvedExpressionCount + unresolvedExpressionCount);
+ buffer.writeln(" expressions:");
+ for (Expression expression in _unresolvedExpressions) {
+ buffer.write(" ");
+ buffer.write(expression.toString());
+ buffer.write(" (");
+ buffer.write(_getFileName(expression));
+ buffer.write(" : ");
+ buffer.write(expression.offset);
+ buffer.writeln(")");
+ }
+ }
+ int invalidlyPropagatedExpressionCount =
+ _invalidlyPropagatedExpressions.length;
+ if (invalidlyPropagatedExpressionCount > 0) {
+ buffer.writeln("Incorrectly propagated ");
+ buffer.write(invalidlyPropagatedExpressionCount);
+ buffer.write(" of ");
+ buffer.write(_propagatedExpressionCount);
+ buffer.writeln(" expressions:");
+ for (Expression expression in _invalidlyPropagatedExpressions) {
+ buffer.write(" ");
+ buffer.write(expression.toString());
+ buffer.write(" [");
+ buffer.write(expression.staticType.displayName);
+ buffer.write(", ");
+ buffer.write(expression.propagatedType.displayName);
+ buffer.writeln("]");
+ buffer.write(" ");
+ buffer.write(_getFileName(expression));
+ buffer.write(" : ");
+ buffer.write(expression.offset);
+ buffer.writeln(")");
+ }
+ }
+ fail(buffer.toString());
+ }
+ }
+
+ @override
+ Object visitBreakStatement(BreakStatement node) => null;
+
+ @override
+ Object visitCommentReference(CommentReference node) => null;
+
+ @override
+ Object visitContinueStatement(ContinueStatement node) => null;
+
+ @override
+ Object visitExportDirective(ExportDirective node) => null;
+
+ @override
+ Object visitExpression(Expression node) {
+ node.visitChildren(this);
+ DartType staticType = node.staticType;
+ if (staticType == null) {
+ _unresolvedExpressions.add(node);
+ } else {
+ _resolvedExpressionCount++;
+ DartType propagatedType = node.propagatedType;
+ if (propagatedType != null) {
+ _propagatedExpressionCount++;
+ if (!propagatedType.isMoreSpecificThan(staticType)) {
+ _invalidlyPropagatedExpressions.add(node);
+ }
+ }
+ }
+ return null;
+ }
+
+ @override
+ Object visitImportDirective(ImportDirective node) => null;
+
+ @override
+ Object visitLabel(Label node) => null;
+
+ @override
+ Object visitLibraryIdentifier(LibraryIdentifier node) => null;
+
+ @override
+ Object visitPrefixedIdentifier(PrefixedIdentifier node) {
+ // In cases where we have a prefixed identifier where the prefix is dynamic,
+ // we don't want to assert that the node will have a type.
+ if (node.staticType == null && node.prefix.staticType.isDynamic) {
+ return null;
+ }
+ return super.visitPrefixedIdentifier(node);
+ }
+
+ @override
+ Object visitSimpleIdentifier(SimpleIdentifier node) {
+ // In cases where identifiers are being used for something other than an
+ // expressions, then they can be ignored.
+ AstNode parent = node.parent;
+ if (parent is MethodInvocation && identical(node, parent.methodName)) {
+ return null;
+ } else if (parent is RedirectingConstructorInvocation &&
+ identical(node, parent.constructorName)) {
+ return null;
+ } else if (parent is SuperConstructorInvocation &&
+ identical(node, parent.constructorName)) {
+ return null;
+ } else if (parent is ConstructorName && identical(node, parent.name)) {
+ return null;
+ } else if (parent is ConstructorFieldInitializer &&
+ identical(node, parent.fieldName)) {
+ return null;
+ } else if (node.staticElement is PrefixElement) {
+ // Prefixes don't have a type.
+ return null;
+ }
+ return super.visitSimpleIdentifier(node);
+ }
+
+ @override
+ Object visitTypeName(TypeName node) {
+ // Note: do not visit children from this node, the child SimpleIdentifier in
+ // TypeName (i.e. "String") does not have a static type defined.
+ if (node.type == null) {
+ _unresolvedTypes.add(node);
+ } else {
+ _resolvedTypeCount++;
+ }
+ return null;
+ }
+
+ String _getFileName(AstNode node) {
+ // TODO (jwren) there are two copies of this method, one here and one in
+ // ResolutionVerifier, they should be resolved into a single method
+ if (node != null) {
+ AstNode root = node.root;
+ if (root is CompilationUnit) {
+ CompilationUnit rootCU = root;
+ if (rootCU.element != null) {
+ return rootCU.element.source.fullName;
+ } else {
+ return "<unknown file- CompilationUnit.getElement() returned null>";
+ }
+ } else {
+ return "<unknown file- CompilationUnit.getRoot() is not a CompilationUnit>";
+ }
+ }
+ return "<unknown file- ASTNode is null>";
+ }
+}
+
+/**
+ * The class `StrictModeTest` contains tests to ensure that the correct errors and warnings
+ * are reported when the analysis engine is run in strict mode.
+ */
+@reflectiveTest
+class StrictModeTest extends ResolverTestCase {
+ void fail_for() {
+ Source source = addSource(r'''
+int f(List<int> list) {
+ num sum = 0;
+ for (num i = 0; i < list.length; i++) {
+ sum += list[i];
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]);
+ }
+
+ @override
+ void setUp() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.hint = false;
+ resetWithOptions(options);
+ }
+
+ void test_assert_is() {
+ Source source = addSource(r'''
+int f(num n) {
+ assert (n is int);
+ return n & 0x0F;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]);
+ }
+
+ void test_conditional_and_is() {
+ Source source = addSource(r'''
+int f(num n) {
+ return (n is int && n > 0) ? n & 0x0F : 0;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_conditional_is() {
+ Source source = addSource(r'''
+int f(num n) {
+ return (n is int) ? n & 0x0F : 0;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_conditional_isNot() {
+ Source source = addSource(r'''
+int f(num n) {
+ return (n is! int) ? 0 : n & 0x0F;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]);
+ }
+
+ void test_conditional_or_is() {
+ Source source = addSource(r'''
+int f(num n) {
+ return (n is! int || n < 0) ? 0 : n & 0x0F;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]);
+ }
+
+ void test_forEach() {
+ Source source = addSource(r'''
+int f(List<int> list) {
+ num sum = 0;
+ for (num n in list) {
+ sum += n & 0x0F;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]);
+ }
+
+ void test_if_and_is() {
+ Source source = addSource(r'''
+int f(num n) {
+ if (n is int && n > 0) {
+ return n & 0x0F;
+ }
+ return 0;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_if_is() {
+ Source source = addSource(r'''
+int f(num n) {
+ if (n is int) {
+ return n & 0x0F;
+ }
+ return 0;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_if_isNot() {
+ Source source = addSource(r'''
+int f(num n) {
+ if (n is! int) {
+ return 0;
+ } else {
+ return n & 0x0F;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]);
+ }
+
+ void test_if_isNot_abrupt() {
+ Source source = addSource(r'''
+int f(num n) {
+ if (n is! int) {
+ return 0;
+ }
+ return n & 0x0F;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]);
+ }
+
+ void test_if_or_is() {
+ Source source = addSource(r'''
+int f(num n) {
+ if (n is! int || n < 0) {
+ return 0;
+ } else {
+ return n & 0x0F;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]);
+ }
+
+ void test_localVar() {
+ Source source = addSource(r'''
+int f() {
+ num n = 1234;
+ return n & 0x0F;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]);
+ }
+}
+
+/**
+ * Strong mode static analyzer end to end tests
+ */
+@reflectiveTest
+class StrongModeStaticTypeAnalyzer2Test extends _StaticTypeAnalyzer2TestShared {
+ void setUp() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.strongMode = true;
+ resetWithOptions(options);
+ }
+
+ void test_dynamicObjectGetter_hashCode() {
+ String code = r'''
+main() {
+ dynamic a = null;
+ var foo = a.hashCode;
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'int');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_dynamicObjectMethod_toString() {
+ String code = r'''
+main() {
+ dynamic a = null;
+ var foo = a.toString();
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'String');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_pseudoGeneric_max_doubleDouble() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1.0, 2.0);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'double');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_pseudoGeneric_max_doubleInt() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1.0, 2);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'num');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_pseudoGeneric_max_intDouble() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1, 2.0);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'num');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_pseudoGeneric_max_intInt() {
+ String code = r'''
+import 'dart:math';
+main() {
+ var foo = max(1, 2);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'int');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_pseudoGeneric_then() {
+ String code = r'''
+import 'dart:async';
+String toString(int x) => x.toString();
+main() {
+ Future<int> bar = null;
+ var foo = bar.then(toString);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+
+ expect(declaration.initializer.staticType.toString(), "Future<String>");
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_ternaryOperator_null_left() {
+ String code = r'''
+main() {
+ var foo = (true) ? null : 3;
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'int');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
+ void test_ternaryOperator_null_right() {
+ String code = r'''
+main() {
+ var foo = (true) ? 3 : null;
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'int');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+}
+
+@reflectiveTest
+class StrongModeTypePropagationTest extends ResolverTestCase {
+ @override
+ void setUp() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.strongMode = true;
+ resetWithOptions(options);
+ }
+
+ void test_foreachInference_dynamic_disabled() {
+ String code = r'''
+main() {
+ var list = <int>[];
+ for (dynamic v in list) {
+ v; // marker
+ }
+}''';
+ _assertPropagatedIterationType(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_foreachInference_reusedVar_disabled() {
+ String code = r'''
+main() {
+ var list = <int>[];
+ var v;
+ for (v in list) {
+ v; // marker
+ }
+}''';
+ _assertPropagatedIterationType(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_foreachInference_var() {
+ String code = r'''
+main() {
+ var list = <int>[];
+ for (var v in list) {
+ v; // marker
+ }
+}''';
+ _assertPropagatedIterationType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_foreachInference_var_iterable() {
+ String code = r'''
+main() {
+ Iterable<int> list = <int>[];
+ for (var v in list) {
+ v; // marker
+ }
+}''';
+ _assertPropagatedIterationType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_foreachInference_var_stream() {
+ String code = r'''
+import 'dart:async';
+main() async {
+ Stream<int> stream = null;
+ await for (var v in stream) {
+ v; // marker
+ }
+}''';
+ _assertPropagatedIterationType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_bottom_disabled() {
+ String code = r'''
+main() {
+ var v = null;
+ v; // marker
+}''';
+ _assertPropagatedAssignedType(code, typeProvider.dynamicType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.dynamicType, null);
+ }
+
+ void test_localVariableInference_constant() {
+ String code = r'''
+main() {
+ var v = 3;
+ v; // marker
+}''';
+ _assertPropagatedAssignedType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_declaredType_disabled() {
+ String code = r'''
+main() {
+ dynamic v = 3;
+ v; // marker
+}''';
+ _assertPropagatedAssignedType(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_localVariableInference_noInitializer_disabled() {
+ String code = r'''
+main() {
+ var v;
+ v = 3;
+ v; // marker
+}''';
+ _assertPropagatedAssignedType(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_localVariableInference_transitive_field_inferred_lexical() {
+ if (!AnalysisEngine.instance.useTaskModel) {
+ return;
+ }
+ String code = r'''
+class A {
+ final x = 3;
+ f() {
+ var v = x;
+ return v; // marker
+ }
+}
+main() {
+}
+''';
+ _assertPropagatedAssignedType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_field_inferred_reversed() {
+ if (!AnalysisEngine.instance.useTaskModel) {
+ return;
+ }
+ String code = r'''
+class A {
+ f() {
+ var v = x;
+ return v; // marker
+ }
+ final x = 3;
+}
+main() {
+}
+''';
+ _assertPropagatedAssignedType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_field_lexical() {
+ String code = r'''
+class A {
+ int x = 3;
+ f() {
+ var v = x;
+ return v; // marker
+ }
+}
+main() {
+}
+''';
+ _assertPropagatedAssignedType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_field_reversed() {
+ String code = r'''
+class A {
+ f() {
+ var v = x;
+ return v; // marker
+ }
+ int x = 3;
+}
+main() {
+}
+''';
+ _assertPropagatedAssignedType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_list_local() {
+ String code = r'''
+main() {
+ var x = <int>[3];
+ var v = x[0];
+ v; // marker
+}''';
+ _assertPropagatedAssignedType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_local() {
+ String code = r'''
+main() {
+ var x = 3;
+ var v = x;
+ v; // marker
+}''';
+ _assertPropagatedAssignedType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_toplevel_inferred_lexical() {
+ if (!AnalysisEngine.instance.useTaskModel) {
+ return;
+ }
+ String code = r'''
+final x = 3;
+main() {
+ var v = x;
+ v; // marker
+}
+''';
+ _assertPropagatedAssignedType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_toplevel_inferred_reversed() {
+ if (!AnalysisEngine.instance.useTaskModel) {
+ return;
+ }
+ String code = r'''
+main() {
+ var v = x;
+ v; // marker
+}
+final x = 3;
+''';
+ _assertPropagatedAssignedType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_toplevel_lexical() {
+ String code = r'''
+int x = 3;
+main() {
+ var v = x;
+ v; // marker
+}
+''';
+ _assertPropagatedAssignedType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+
+ void test_localVariableInference_transitive_toplevel_reversed() {
+ String code = r'''
+main() {
+ var v = x;
+ v; // marker
+}
+int x = 3;
+''';
+ _assertPropagatedAssignedType(code, typeProvider.intType, null);
+ _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+ }
+}
+
+@reflectiveTest
+class SubtypeManagerTest extends EngineTestCase {
+ /**
+ * The inheritance manager being tested.
+ */
+ SubtypeManager _subtypeManager;
+
+ /**
+ * The compilation unit element containing all of the types setup in each test.
+ */
+ CompilationUnitElementImpl _definingCompilationUnit;
+
+ @override
+ void setUp() {
+ super.setUp();
+ AnalysisContext context = AnalysisContextFactory.contextWithCore();
+ FileBasedSource source =
+ new FileBasedSource(FileUtilities2.createFile("/test.dart"));
+ _definingCompilationUnit = new CompilationUnitElementImpl("test.dart");
+ _definingCompilationUnit.librarySource =
+ _definingCompilationUnit.source = source;
+ LibraryElementImpl definingLibrary =
+ ElementFactory.library(context, "test");
+ definingLibrary.definingCompilationUnit = _definingCompilationUnit;
+ _subtypeManager = new SubtypeManager();
+ }
+
+ void test_computeAllSubtypes_infiniteLoop() {
+ //
+ // class A extends B
+ // class B extends A
+ //
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ classA.supertype = classB.type;
+ _definingCompilationUnit.types = <ClassElement>[classA, classB];
+ HashSet<ClassElement> subtypesOfA =
+ _subtypeManager.computeAllSubtypes(classA);
+ List<ClassElement> arraySubtypesOfA = new List.from(subtypesOfA);
+ expect(subtypesOfA, hasLength(2));
+ expect(arraySubtypesOfA, unorderedEquals([classA, classB]));
+ }
+
+ void test_computeAllSubtypes_manyRecursiveSubtypes() {
+ //
+ // class A
+ // class B extends A
+ // class C extends B
+ // class D extends B
+ // class E extends B
+ //
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ ClassElementImpl classC = ElementFactory.classElement("C", classB.type);
+ ClassElementImpl classD = ElementFactory.classElement("D", classB.type);
+ ClassElementImpl classE = ElementFactory.classElement("E", classB.type);
+ _definingCompilationUnit.types = <ClassElement>[
+ classA,
+ classB,
+ classC,
+ classD,
+ classE
+ ];
+ HashSet<ClassElement> subtypesOfA =
+ _subtypeManager.computeAllSubtypes(classA);
+ List<ClassElement> arraySubtypesOfA = new List.from(subtypesOfA);
+ HashSet<ClassElement> subtypesOfB =
+ _subtypeManager.computeAllSubtypes(classB);
+ List<ClassElement> arraySubtypesOfB = new List.from(subtypesOfB);
+ expect(subtypesOfA, hasLength(4));
+ expect(arraySubtypesOfA, unorderedEquals([classB, classC, classD, classE]));
+ expect(subtypesOfB, hasLength(3));
+ expect(arraySubtypesOfB, unorderedEquals([classC, classD, classE]));
+ }
+
+ void test_computeAllSubtypes_noSubtypes() {
+ //
+ // class A
+ //
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ _definingCompilationUnit.types = <ClassElement>[classA];
+ HashSet<ClassElement> subtypesOfA =
+ _subtypeManager.computeAllSubtypes(classA);
+ expect(subtypesOfA, hasLength(0));
+ }
+
+ void test_computeAllSubtypes_oneSubtype() {
+ //
+ // class A
+ // class B extends A
+ //
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
+ _definingCompilationUnit.types = <ClassElement>[classA, classB];
+ HashSet<ClassElement> subtypesOfA =
+ _subtypeManager.computeAllSubtypes(classA);
+ List<ClassElement> arraySubtypesOfA = new List.from(subtypesOfA);
+ expect(subtypesOfA, hasLength(1));
+ expect(arraySubtypesOfA, unorderedEquals([classB]));
+ }
+}
+
+@reflectiveTest
+class TypeOverrideManagerTest extends EngineTestCase {
+ void test_exitScope_noScopes() {
+ TypeOverrideManager manager = new TypeOverrideManager();
+ try {
+ manager.exitScope();
+ fail("Expected IllegalStateException");
+ } on IllegalStateException {
+ // Expected
+ }
+ }
+
+ void test_exitScope_oneScope() {
+ TypeOverrideManager manager = new TypeOverrideManager();
+ manager.enterScope();
+ manager.exitScope();
+ try {
+ manager.exitScope();
+ fail("Expected IllegalStateException");
+ } on IllegalStateException {
+ // Expected
+ }
+ }
+
+ void test_exitScope_twoScopes() {
+ TypeOverrideManager manager = new TypeOverrideManager();
+ manager.enterScope();
+ manager.exitScope();
+ manager.enterScope();
+ manager.exitScope();
+ try {
+ manager.exitScope();
+ fail("Expected IllegalStateException");
+ } on IllegalStateException {
+ // Expected
+ }
+ }
+
+ void test_getType_enclosedOverride() {
+ TypeOverrideManager manager = new TypeOverrideManager();
+ LocalVariableElementImpl element =
+ ElementFactory.localVariableElement2("v");
+ InterfaceType type = ElementFactory.classElement2("C").type;
+ manager.enterScope();
+ manager.setType(element, type);
+ manager.enterScope();
+ expect(manager.getType(element), same(type));
+ }
+
+ void test_getType_immediateOverride() {
+ TypeOverrideManager manager = new TypeOverrideManager();
+ LocalVariableElementImpl element =
+ ElementFactory.localVariableElement2("v");
+ InterfaceType type = ElementFactory.classElement2("C").type;
+ manager.enterScope();
+ manager.setType(element, type);
+ expect(manager.getType(element), same(type));
+ }
+
+ void test_getType_noOverride() {
+ TypeOverrideManager manager = new TypeOverrideManager();
+ manager.enterScope();
+ expect(manager.getType(ElementFactory.localVariableElement2("v")), isNull);
+ }
+
+ void test_getType_noScope() {
+ TypeOverrideManager manager = new TypeOverrideManager();
+ expect(manager.getType(ElementFactory.localVariableElement2("v")), isNull);
+ }
+}
+
+@reflectiveTest
+class TypePropagationTest extends ResolverTestCase {
+ void fail_finalPropertyInducingVariable_classMember_instance() {
+ addNamedSource(
+ "/lib.dart",
+ r'''
+class A {
+ final v = 0;
+}''');
+ String code = r'''
+import 'lib.dart';
+f(A a) {
+ return a.v; // marker
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void fail_finalPropertyInducingVariable_classMember_instance_inherited() {
+ addNamedSource(
+ "/lib.dart",
+ r'''
+class A {
+ final v = 0;
+}''');
+ String code = r'''
+import 'lib.dart';
+class B extends A {
+ m() {
+ return v; // marker
+ }
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void fail_finalPropertyInducingVariable_classMember_instance_propagatedTarget() {
+ addNamedSource(
+ "/lib.dart",
+ r'''
+class A {
+ final v = 0;
+}''');
+ String code = r'''
+import 'lib.dart';
+f(p) {
+ if (p is A) {
+ return p.v; // marker
+ }
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void fail_finalPropertyInducingVariable_classMember_instance_unprefixed() {
+ String code = r'''
+class A {
+ final v = 0;
+ m() {
+ v; // marker
+ }
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void fail_finalPropertyInducingVariable_classMember_static() {
+ addNamedSource(
+ "/lib.dart",
+ r'''
+class A {
+ static final V = 0;
+}''');
+ String code = r'''
+import 'lib.dart';
+f() {
+ return A.V; // marker
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void fail_finalPropertyInducingVariable_topLevelVaraible_prefixed() {
+ addNamedSource("/lib.dart", "final V = 0;");
+ String code = r'''
+import 'lib.dart' as p;
+f() {
+ var v2 = p.V; // marker prefixed
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void fail_finalPropertyInducingVariable_topLevelVaraible_simple() {
+ addNamedSource("/lib.dart", "final V = 0;");
+ String code = r'''
+import 'lib.dart';
+f() {
+ return V; // marker simple
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void fail_mergePropagatedTypesAtJoinPoint_1() {
+ // https://code.google.com/p/dart/issues/detail?id=19929
+ _assertTypeOfMarkedExpression(
+ r'''
+f1(x) {
+ var y = [];
+ if (x) {
+ y = 0;
+ } else {
+ y = '';
+ }
+ // Propagated type is [List] here: incorrect.
+ // Best we can do is [Object]?
+ return y; // marker
+}''',
+ null,
+ typeProvider.dynamicType);
+ }
+
+ void fail_mergePropagatedTypesAtJoinPoint_2() {
+ // https://code.google.com/p/dart/issues/detail?id=19929
+ _assertTypeOfMarkedExpression(
+ r'''
+f2(x) {
+ var y = [];
+ if (x) {
+ y = 0;
+ } else {
+ }
+ // Propagated type is [List] here: incorrect.
+ // Best we can do is [Object]?
+ return y; // marker
+}''',
+ null,
+ typeProvider.dynamicType);
+ }
+
+ void fail_mergePropagatedTypesAtJoinPoint_3() {
+ // https://code.google.com/p/dart/issues/detail?id=19929
+ _assertTypeOfMarkedExpression(
+ r'''
+f4(x) {
+ var y = [];
+ if (x) {
+ y = 0;
+ } else {
+ y = 1.5;
+ }
+ // Propagated type is [List] here: incorrect.
+ // A correct answer is the least upper bound of [int] and [double],
+ // i.e. [num].
+ return y; // marker
+}''',
+ null,
+ typeProvider.numType);
+ }
+
+ void fail_mergePropagatedTypesAtJoinPoint_5() {
+ // https://code.google.com/p/dart/issues/detail?id=19929
+ _assertTypeOfMarkedExpression(
+ r'''
+f6(x,y) {
+ var z = [];
+ if (x || (z = y) < 0) {
+ } else {
+ z = 0;
+ }
+ // Propagated type is [List] here: incorrect.
+ // Best we can do is [Object]?
+ return z; // marker
+}''',
+ null,
+ typeProvider.dynamicType);
+ }
+
+ void fail_mergePropagatedTypesAtJoinPoint_7() {
+ // https://code.google.com/p/dart/issues/detail?id=19929
+ //
+ // In general [continue]s are unsafe for the purposes of
+ // [isAbruptTerminationStatement].
+ //
+ // This is like example 6, but less tricky: the code in the branch that
+ // [continue]s is in effect after the [if].
+ String code = r'''
+f() {
+ var x = 0;
+ var c = false;
+ var d = true;
+ while (d) {
+ if (c) {
+ d = false;
+ } else {
+ x = '';
+ c = true;
+ continue;
+ }
+ x; // marker
+ }
+}''';
+ DartType t = _findMarkedIdentifier(code, "; // marker").propagatedType;
+ expect(typeProvider.intType.isSubtypeOf(t), isTrue);
+ expect(typeProvider.stringType.isSubtypeOf(t), isTrue);
+ }
+
+ void fail_mergePropagatedTypesAtJoinPoint_8() {
+ // https://code.google.com/p/dart/issues/detail?id=19929
+ //
+ // In nested loops [breaks]s are unsafe for the purposes of
+ // [isAbruptTerminationStatement].
+ //
+ // This is a combination of 6 and 7: we use an unlabeled [break]
+ // like a continue for the outer loop / like a labeled [break] to
+ // jump just above the [if].
+ String code = r'''
+f() {
+ var x = 0;
+ var c = false;
+ var d = true;
+ while (d) {
+ while (d) {
+ if (c) {
+ d = false;
+ } else {
+ x = '';
+ c = true;
+ break;
+ }
+ x; // marker
+ }
+ }
+}''';
+ DartType t = _findMarkedIdentifier(code, "; // marker").propagatedType;
+ expect(typeProvider.intType.isSubtypeOf(t), isTrue);
+ expect(typeProvider.stringType.isSubtypeOf(t), isTrue);
+ }
+
+ void fail_propagatedReturnType_functionExpression() {
+ // TODO(scheglov) disabled because we don't resolve function expression
+ String code = r'''
+main() {
+ var v = (() {return 42;})();
+}''';
+ _assertPropagatedAssignedType(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_as() {
+ Source source = addSource(r'''
+class A {
+ bool get g => true;
+}
+A f(var p) {
+ if ((p as A).g) {
+ return p;
+ } else {
+ return null;
+ }
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ ClassDeclaration classA = unit.declarations[0] as ClassDeclaration;
+ InterfaceType typeA = classA.element.type;
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ IfStatement ifStatement = body.block.statements[0] as IfStatement;
+ ReturnStatement statement =
+ (ifStatement.thenStatement as Block).statements[0] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeA));
+ }
+
+ void test_assert() {
+ Source source = addSource(r'''
+class A {}
+A f(var p) {
+ assert (p is A);
+ return p;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ ClassDeclaration classA = unit.declarations[0] as ClassDeclaration;
+ InterfaceType typeA = classA.element.type;
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[1] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeA));
+ }
+
+ void test_assignment() {
+ Source source = addSource(r'''
+f() {
+ var v;
+ v = 0;
+ return v;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[2] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeProvider.intType));
+ }
+
+ void test_assignment_afterInitializer() {
+ Source source = addSource(r'''
+f() {
+ var v = 0;
+ v = 1.0;
+ return v;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[2] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeProvider.doubleType));
+ }
+
+ void test_assignment_null() {
+ String code = r'''
+main() {
+ int v; // declare
+ v = null;
+ return v; // return
+}''';
+ CompilationUnit unit;
+ {
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ unit = resolveCompilationUnit(source, library);
+ }
+ {
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ unit, code, "v; // declare", (node) => node is SimpleIdentifier);
+ expect(identifier.staticType, same(typeProvider.intType));
+ expect(identifier.propagatedType, same(null));
+ }
+ {
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ unit, code, "v = null;", (node) => node is SimpleIdentifier);
+ expect(identifier.staticType, same(typeProvider.intType));
+ expect(identifier.propagatedType, same(null));
+ }
+ {
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ unit, code, "v; // return", (node) => node is SimpleIdentifier);
+ expect(identifier.staticType, same(typeProvider.intType));
+ expect(identifier.propagatedType, same(null));
+ }
+ }
+
+ void test_CanvasElement_getContext() {
+ String code = r'''
+import 'dart:html';
+main(CanvasElement canvas) {
+ var context = canvas.getContext('2d');
+}''';
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ unit, code, "context", (node) => node is SimpleIdentifier);
+ expect(identifier.propagatedType.name, "CanvasRenderingContext2D");
+ }
+
+ void test_forEach() {
+ String code = r'''
+main() {
+ var list = <String> [];
+ for (var e in list) {
+ e;
+ }
+}''';
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ InterfaceType stringType = typeProvider.stringType;
+ // in the declaration
+ {
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ unit, code, "e in", (node) => node is SimpleIdentifier);
+ expect(identifier.propagatedType, same(stringType));
+ }
+ // in the loop body
+ {
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ unit, code, "e;", (node) => node is SimpleIdentifier);
+ expect(identifier.propagatedType, same(stringType));
+ }
+ }
+
+ void test_forEach_async() {
+ String code = r'''
+import 'dart:async';
+f(Stream<String> stream) async {
+ await for (var e in stream) {
+ e;
+ }
+}''';
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ InterfaceType stringType = typeProvider.stringType;
+ // in the declaration
+ {
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ unit, code, "e in", (node) => node is SimpleIdentifier);
+ expect(identifier.propagatedType, same(stringType));
+ }
+ // in the loop body
+ {
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ unit, code, "e;", (node) => node is SimpleIdentifier);
+ expect(identifier.propagatedType, same(stringType));
+ }
+ }
+
+ void test_functionExpression_asInvocationArgument() {
+ String code = r'''
+class MyMap<K, V> {
+ forEach(f(K key, V value)) {}
+}
+f(MyMap<int, String> m) {
+ m.forEach((k, v) {
+ k;
+ v;
+ });
+}''';
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ // k
+ DartType intType = typeProvider.intType;
+ FormalParameter kParameter = EngineTestCase.findNode(
+ unit, code, "k, ", (node) => node is SimpleFormalParameter);
+ expect(kParameter.identifier.propagatedType, same(intType));
+ SimpleIdentifier kIdentifier = EngineTestCase.findNode(
+ unit, code, "k;", (node) => node is SimpleIdentifier);
+ expect(kIdentifier.propagatedType, same(intType));
+ expect(kIdentifier.staticType, same(typeProvider.dynamicType));
+ // v
+ DartType stringType = typeProvider.stringType;
+ FormalParameter vParameter = EngineTestCase.findNode(
+ unit, code, "v)", (node) => node is SimpleFormalParameter);
+ expect(vParameter.identifier.propagatedType, same(stringType));
+ SimpleIdentifier vIdentifier = EngineTestCase.findNode(
+ unit, code, "v;", (node) => node is SimpleIdentifier);
+ expect(vIdentifier.propagatedType, same(stringType));
+ expect(vIdentifier.staticType, same(typeProvider.dynamicType));
+ }
+
+ void test_functionExpression_asInvocationArgument_fromInferredInvocation() {
+ String code = r'''
+class MyMap<K, V> {
+ forEach(f(K key, V value)) {}
+}
+f(MyMap<int, String> m) {
+ var m2 = m;
+ m2.forEach((k, v) {});
+}''';
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ // k
+ DartType intType = typeProvider.intType;
+ FormalParameter kParameter = EngineTestCase.findNode(
+ unit, code, "k, ", (node) => node is SimpleFormalParameter);
+ expect(kParameter.identifier.propagatedType, same(intType));
+ // v
+ DartType stringType = typeProvider.stringType;
+ FormalParameter vParameter = EngineTestCase.findNode(
+ unit, code, "v)", (node) => node is SimpleFormalParameter);
+ expect(vParameter.identifier.propagatedType, same(stringType));
+ }
+
+ void test_functionExpression_asInvocationArgument_functionExpressionInvocation() {
+ String code = r'''
+main() {
+ (f(String value)) {} ((v) {
+ v;
+ });
+}''';
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ // v
+ DartType dynamicType = typeProvider.dynamicType;
+ DartType stringType = typeProvider.stringType;
+ FormalParameter vParameter = EngineTestCase.findNode(
+ unit, code, "v)", (node) => node is FormalParameter);
+ expect(vParameter.identifier.propagatedType, same(stringType));
+ expect(vParameter.identifier.staticType, same(dynamicType));
+ SimpleIdentifier vIdentifier = EngineTestCase.findNode(
+ unit, code, "v;", (node) => node is SimpleIdentifier);
+ expect(vIdentifier.propagatedType, same(stringType));
+ expect(vIdentifier.staticType, same(dynamicType));
+ }
+
+ void test_functionExpression_asInvocationArgument_keepIfLessSpecific() {
+ String code = r'''
+class MyList {
+ forEach(f(Object value)) {}
+}
+f(MyList list) {
+ list.forEach((int v) {
+ v;
+ });
+}''';
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ // v
+ DartType intType = typeProvider.intType;
+ FormalParameter vParameter = EngineTestCase.findNode(
+ unit, code, "v)", (node) => node is SimpleFormalParameter);
+ expect(vParameter.identifier.propagatedType, same(null));
+ expect(vParameter.identifier.staticType, same(intType));
+ SimpleIdentifier vIdentifier = EngineTestCase.findNode(
+ unit, code, "v;", (node) => node is SimpleIdentifier);
+ expect(vIdentifier.staticType, same(intType));
+ expect(vIdentifier.propagatedType, same(null));
+ }
+
+ void test_functionExpression_asInvocationArgument_notSubtypeOfStaticType() {
+ String code = r'''
+class A {
+ m(void f(int i)) {}
+}
+x() {
+ A a = new A();
+ a.m(() => 0);
+}''';
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertErrors(source, [StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ // () => 0
+ FunctionExpression functionExpression = EngineTestCase.findNode(
+ unit, code, "() => 0)", (node) => node is FunctionExpression);
+ expect((functionExpression.staticType as FunctionType).parameters.length,
+ same(0));
+ expect(functionExpression.propagatedType, same(null));
+ }
+
+ void test_functionExpression_asInvocationArgument_replaceIfMoreSpecific() {
+ String code = r'''
+class MyList<E> {
+ forEach(f(E value)) {}
+}
+f(MyList<String> list) {
+ list.forEach((Object v) {
+ v;
+ });
+}''';
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ // v
+ DartType stringType = typeProvider.stringType;
+ FormalParameter vParameter = EngineTestCase.findNode(
+ unit, code, "v)", (node) => node is SimpleFormalParameter);
+ expect(vParameter.identifier.propagatedType, same(stringType));
+ expect(vParameter.identifier.staticType, same(typeProvider.objectType));
+ SimpleIdentifier vIdentifier = EngineTestCase.findNode(
+ unit, code, "v;", (node) => node is SimpleIdentifier);
+ expect(vIdentifier.propagatedType, same(stringType));
+ }
+
+ void test_Future_then() {
+ String code = r'''
+import 'dart:async';
+main(Future<int> firstFuture) {
+ firstFuture.then((p1) {
+ return 1.0;
+ }).then((p2) {
+ return new Future<String>.value('str');
+ }).then((p3) {
+ });
+}''';
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ // p1
+ FormalParameter p1 = EngineTestCase.findNode(
+ unit, code, "p1) {", (node) => node is SimpleFormalParameter);
+ expect(p1.identifier.propagatedType, same(typeProvider.intType));
+ // p2
+ FormalParameter p2 = EngineTestCase.findNode(
+ unit, code, "p2) {", (node) => node is SimpleFormalParameter);
+ expect(p2.identifier.propagatedType, same(typeProvider.doubleType));
+ // p3
+ FormalParameter p3 = EngineTestCase.findNode(
+ unit, code, "p3) {", (node) => node is SimpleFormalParameter);
+ expect(p3.identifier.propagatedType, same(typeProvider.stringType));
+ }
+
+ void test_initializer() {
+ Source source = addSource(r'''
+f() {
+ var v = 0;
+ return v;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ NodeList<Statement> statements = body.block.statements;
+ // Type of 'v' in declaration.
+ {
+ VariableDeclarationStatement statement =
+ statements[0] as VariableDeclarationStatement;
+ SimpleIdentifier variableName = statement.variables.variables[0].name;
+ expect(variableName.staticType, same(typeProvider.dynamicType));
+ expect(variableName.propagatedType, same(typeProvider.intType));
+ }
+ // Type of 'v' in reference.
+ {
+ ReturnStatement statement = statements[1] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeProvider.intType));
+ }
+ }
+
+ void test_initializer_dereference() {
+ Source source = addSource(r'''
+f() {
+ var v = 'String';
+ v.
+}''');
+ LibraryElement library = resolve2(source);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ExpressionStatement statement =
+ body.block.statements[1] as ExpressionStatement;
+ PrefixedIdentifier invocation = statement.expression as PrefixedIdentifier;
+ SimpleIdentifier variableName = invocation.prefix;
+ expect(variableName.propagatedType, same(typeProvider.stringType));
+ }
+
+ void test_initializer_hasStaticType() {
+ Source source = addSource(r'''
+f() {
+ int v = 0;
+ return v;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ NodeList<Statement> statements = body.block.statements;
+ // Type of 'v' in declaration.
+ {
+ VariableDeclarationStatement statement =
+ statements[0] as VariableDeclarationStatement;
+ SimpleIdentifier variableName = statement.variables.variables[0].name;
+ expect(variableName.staticType, same(typeProvider.intType));
+ expect(variableName.propagatedType, isNull);
+ }
+ // Type of 'v' in reference.
+ {
+ ReturnStatement statement = statements[1] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.staticType, same(typeProvider.intType));
+ expect(variableName.propagatedType, isNull);
+ }
+ }
+
+ void test_initializer_hasStaticType_parameterized() {
+ Source source = addSource(r'''
+f() {
+ List<int> v = <int>[];
+ return v;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ NodeList<Statement> statements = body.block.statements;
+ // Type of 'v' in declaration.
+ {
+ VariableDeclarationStatement statement =
+ statements[0] as VariableDeclarationStatement;
+ SimpleIdentifier variableName = statement.variables.variables[0].name;
+ expect(variableName.staticType, isNotNull);
+ expect(variableName.propagatedType, isNull);
+ }
+ // Type of 'v' in reference.
+ {
+ ReturnStatement statement = statements[1] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.staticType, isNotNull);
+ expect(variableName.propagatedType, isNull);
+ }
+ }
+
+ void test_initializer_null() {
+ String code = r'''
+main() {
+ int v = null;
+ return v; // marker
+}''';
+ CompilationUnit unit;
+ {
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ unit = resolveCompilationUnit(source, library);
+ }
+ {
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ unit, code, "v = null;", (node) => node is SimpleIdentifier);
+ expect(identifier.staticType, same(typeProvider.intType));
+ expect(identifier.propagatedType, same(null));
+ }
+ {
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ unit, code, "v; // marker", (node) => node is SimpleIdentifier);
+ expect(identifier.staticType, same(typeProvider.intType));
+ expect(identifier.propagatedType, same(null));
+ }
+ }
+
+ void test_is_conditional() {
+ Source source = addSource(r'''
+class A {}
+A f(var p) {
+ return (p is A) ? p : null;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ ClassDeclaration classA = unit.declarations[0] as ClassDeclaration;
+ InterfaceType typeA = classA.element.type;
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[0] as ReturnStatement;
+ ConditionalExpression conditional =
+ statement.expression as ConditionalExpression;
+ SimpleIdentifier variableName =
+ conditional.thenExpression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeA));
+ }
+
+ void test_is_if() {
+ Source source = addSource(r'''
+class A {}
+A f(var p) {
+ if (p is A) {
+ return p;
+ } else {
+ return null;
+ }
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ // prepare A
+ InterfaceType typeA;
+ {
+ ClassDeclaration classA = unit.declarations[0] as ClassDeclaration;
+ typeA = classA.element.type;
+ }
+ // verify "f"
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ IfStatement ifStatement = body.block.statements[0] as IfStatement;
+ // "p is A"
+ {
+ IsExpression isExpression = ifStatement.condition;
+ SimpleIdentifier variableName = isExpression.expression;
+ expect(variableName.propagatedType, isNull);
+ }
+ // "return p;"
+ {
+ ReturnStatement statement =
+ (ifStatement.thenStatement as Block).statements[0] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeA));
+ }
+ }
+
+ void test_is_if_lessSpecific() {
+ Source source = addSource(r'''
+class A {}
+A f(A p) {
+ if (p is String) {
+ return p;
+ } else {
+ return null;
+ }
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+// ClassDeclaration classA = (ClassDeclaration) unit.getDeclarations().get(0);
+// InterfaceType typeA = classA.getElement().getType();
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ IfStatement ifStatement = body.block.statements[0] as IfStatement;
+ ReturnStatement statement =
+ (ifStatement.thenStatement as Block).statements[0] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(null));
+ }
+
+ void test_is_if_logicalAnd() {
+ Source source = addSource(r'''
+class A {}
+A f(var p) {
+ if (p is A && p != null) {
+ return p;
+ } else {
+ return null;
+ }
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ ClassDeclaration classA = unit.declarations[0] as ClassDeclaration;
+ InterfaceType typeA = classA.element.type;
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ IfStatement ifStatement = body.block.statements[0] as IfStatement;
+ ReturnStatement statement =
+ (ifStatement.thenStatement as Block).statements[0] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeA));
+ }
+
+ void test_is_postConditional() {
+ Source source = addSource(r'''
+class A {}
+A f(var p) {
+ A a = (p is A) ? p : throw null;
+ return p;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ ClassDeclaration classA = unit.declarations[0] as ClassDeclaration;
+ InterfaceType typeA = classA.element.type;
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[1] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeA));
+ }
+
+ void test_is_postIf() {
+ Source source = addSource(r'''
+class A {}
+A f(var p) {
+ if (p is A) {
+ A a = p;
+ } else {
+ return null;
+ }
+ return p;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ ClassDeclaration classA = unit.declarations[0] as ClassDeclaration;
+ InterfaceType typeA = classA.element.type;
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[1] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeA));
+ }
+
+ void test_is_subclass() {
+ Source source = addSource(r'''
+class A {}
+class B extends A {
+ B m() => this;
+}
+A f(A p) {
+ if (p is B) {
+ return p.m();
+ }
+ return p;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration function = unit.declarations[2] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ IfStatement ifStatement = body.block.statements[0] as IfStatement;
+ ReturnStatement statement =
+ (ifStatement.thenStatement as Block).statements[0] as ReturnStatement;
+ MethodInvocation invocation = statement.expression as MethodInvocation;
+ expect(invocation.methodName.staticElement, isNotNull);
+ expect(invocation.methodName.propagatedElement, isNull);
+ }
+
+ void test_is_while() {
+ Source source = addSource(r'''
+class A {}
+A f(var p) {
+ while (p is A) {
+ return p;
+ }
+ return p;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ ClassDeclaration classA = unit.declarations[0] as ClassDeclaration;
+ InterfaceType typeA = classA.element.type;
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ WhileStatement whileStatement = body.block.statements[0] as WhileStatement;
+ ReturnStatement statement =
+ (whileStatement.body as Block).statements[0] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeA));
+ }
+
+ void test_isNot_conditional() {
+ Source source = addSource(r'''
+class A {}
+A f(var p) {
+ return (p is! A) ? null : p;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ ClassDeclaration classA = unit.declarations[0] as ClassDeclaration;
+ InterfaceType typeA = classA.element.type;
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[0] as ReturnStatement;
+ ConditionalExpression conditional =
+ statement.expression as ConditionalExpression;
+ SimpleIdentifier variableName =
+ conditional.elseExpression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeA));
+ }
+
+ void test_isNot_if() {
+ Source source = addSource(r'''
+class A {}
+A f(var p) {
+ if (p is! A) {
+ return null;
+ } else {
+ return p;
+ }
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ ClassDeclaration classA = unit.declarations[0] as ClassDeclaration;
+ InterfaceType typeA = classA.element.type;
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ IfStatement ifStatement = body.block.statements[0] as IfStatement;
+ ReturnStatement statement =
+ (ifStatement.elseStatement as Block).statements[0] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeA));
+ }
+
+ void test_isNot_if_logicalOr() {
+ Source source = addSource(r'''
+class A {}
+A f(var p) {
+ if (p is! A || null == p) {
+ return null;
+ } else {
+ return p;
+ }
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ ClassDeclaration classA = unit.declarations[0] as ClassDeclaration;
+ InterfaceType typeA = classA.element.type;
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ IfStatement ifStatement = body.block.statements[0] as IfStatement;
+ ReturnStatement statement =
+ (ifStatement.elseStatement as Block).statements[0] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeA));
+ }
+
+ void test_isNot_postConditional() {
+ Source source = addSource(r'''
+class A {}
+A f(var p) {
+ A a = (p is! A) ? throw null : p;
+ return p;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ ClassDeclaration classA = unit.declarations[0] as ClassDeclaration;
+ InterfaceType typeA = classA.element.type;
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[1] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeA));
+ }
+
+ void test_isNot_postIf() {
+ Source source = addSource(r'''
+class A {}
+A f(var p) {
+ if (p is! A) {
+ return null;
+ }
+ return p;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ ClassDeclaration classA = unit.declarations[0] as ClassDeclaration;
+ InterfaceType typeA = classA.element.type;
+ FunctionDeclaration function = unit.declarations[1] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[1] as ReturnStatement;
+ SimpleIdentifier variableName = statement.expression as SimpleIdentifier;
+ expect(variableName.propagatedType, same(typeA));
+ }
+
+ void test_issue20904BuggyTypePromotionAtIfJoin_5() {
+ // https://code.google.com/p/dart/issues/detail?id=20904
+ //
+ // This is not an example of the 20904 bug, but rather,
+ // an example of something that one obvious fix changes inadvertently: we
+ // want to avoid using type information from is-checks when it
+ // loses precision. I can't see how to get a bad hint this way, since
+ // it seems the propagated type is not used to generate hints when a
+ // more precise type would cause no hint. For example, for code like the
+ // following, when the propagated type of [x] is [A] -- as happens for the
+ // fix these tests aim to warn against -- there is no warning for
+
+ // calling a method defined on [B] but not [A] (there aren't any, but
+ // pretend), but there is for calling a method not defined on either.
+ // By not overriding the propagated type via an is-check that loses
+ // precision, we get more precise completion under an is-check. However,
+ // I can only imagine strange code would make use of this feature.
+ //
+ // Here the is-check improves precision, so we use it.
+ String code = r'''
+class A {}
+class B extends A {}
+f() {
+ var a = new A();
+ var b = new B();
+ b; // B
+ if (a is B) {
+ return a; // marker
+ }
+}''';
+ DartType tB = _findMarkedIdentifier(code, "; // B").propagatedType;
+ _assertTypeOfMarkedExpression(code, null, tB);
+ }
+
+ void test_issue20904BuggyTypePromotionAtIfJoin_6() {
+ // https://code.google.com/p/dart/issues/detail?id=20904
+ //
+ // The other half of the *_5() test.
+ //
+ // Here the is-check loses precision, so we don't use it.
+ String code = r'''
+class A {}
+class B extends A {}
+f() {
+ var b = new B();
+ b; // B
+ if (b is A) {
+ return b; // marker
+ }
+}''';
+ DartType tB = _findMarkedIdentifier(code, "; // B").propagatedType;
+ _assertTypeOfMarkedExpression(code, null, tB);
+ }
+
+ void test_listLiteral_different() {
+ Source source = addSource(r'''
+f() {
+ var v = [0, '1', 2];
+ return v[2];
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[1] as ReturnStatement;
+ IndexExpression indexExpression = statement.expression as IndexExpression;
+ expect(indexExpression.propagatedType, isNull);
+ }
+
+ void test_listLiteral_same() {
+ Source source = addSource(r'''
+f() {
+ var v = [0, 1, 2];
+ return v[2];
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[1] as ReturnStatement;
+ IndexExpression indexExpression = statement.expression as IndexExpression;
+ expect(indexExpression.propagatedType, isNull);
+ Expression v = indexExpression.target;
+ InterfaceType propagatedType = v.propagatedType as InterfaceType;
+ expect(propagatedType.element, same(typeProvider.listType.element));
+ List<DartType> typeArguments = propagatedType.typeArguments;
+ expect(typeArguments, hasLength(1));
+ expect(typeArguments[0], same(typeProvider.dynamicType));
+ }
+
+ void test_mapLiteral_different() {
+ Source source = addSource(r'''
+f() {
+ var v = {'0' : 0, 1 : '1', '2' : 2};
+ return v;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[1] as ReturnStatement;
+ SimpleIdentifier identifier = statement.expression as SimpleIdentifier;
+ InterfaceType propagatedType = identifier.propagatedType as InterfaceType;
+ expect(propagatedType.element, same(typeProvider.mapType.element));
+ List<DartType> typeArguments = propagatedType.typeArguments;
+ expect(typeArguments, hasLength(2));
+ expect(typeArguments[0], same(typeProvider.dynamicType));
+ expect(typeArguments[1], same(typeProvider.dynamicType));
+ }
+
+ void test_mapLiteral_same() {
+ Source source = addSource(r'''
+f() {
+ var v = {'a' : 0, 'b' : 1, 'c' : 2};
+ return v;
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration;
+ BlockFunctionBody body =
+ function.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[1] as ReturnStatement;
+ SimpleIdentifier identifier = statement.expression as SimpleIdentifier;
+ InterfaceType propagatedType = identifier.propagatedType as InterfaceType;
+ expect(propagatedType.element, same(typeProvider.mapType.element));
+ List<DartType> typeArguments = propagatedType.typeArguments;
+ expect(typeArguments, hasLength(2));
+ expect(typeArguments[0], same(typeProvider.dynamicType));
+ expect(typeArguments[1], same(typeProvider.dynamicType));
+ }
+
+ void test_mergePropagatedTypes_afterIfThen_different() {
+ String code = r'''
+main() {
+ var v = 0;
+ if (v != null) {
+ v = '';
+ }
+ return v;
+}''';
+ {
+ SimpleIdentifier identifier = _findMarkedIdentifier(code, "v;");
+ expect(identifier.propagatedType, null);
+ }
+ {
+ SimpleIdentifier identifier = _findMarkedIdentifier(code, "v = '';");
+ expect(identifier.propagatedType, typeProvider.stringType);
+ }
+ }
+
+ void test_mergePropagatedTypes_afterIfThen_same() {
+ _assertTypeOfMarkedExpression(
+ r'''
+main() {
+ var v = 1;
+ if (v != null) {
+ v = 2;
+ }
+ return v; // marker
+}''',
+ null,
+ typeProvider.intType);
+ }
+
+ void test_mergePropagatedTypes_afterIfThenElse_different() {
+ _assertTypeOfMarkedExpression(
+ r'''
+main() {
+ var v = 1;
+ if (v != null) {
+ v = 2;
+ } else {
+ v = '3';
+ }
+ return v; // marker
+}''',
+ null,
+ null);
+ }
+
+ void test_mergePropagatedTypes_afterIfThenElse_same() {
+ _assertTypeOfMarkedExpression(
+ r'''
+main() {
+ var v = 1;
+ if (v != null) {
+ v = 2;
+ } else {
+ v = 3;
+ }
+ return v; // marker
+}''',
+ null,
+ typeProvider.intType);
+ }
+
+ void test_mergePropagatedTypesAtJoinPoint_4() {
+ // https://code.google.com/p/dart/issues/detail?id=19929
+ _assertTypeOfMarkedExpression(
+ r'''
+f5(x) {
+ var y = [];
+ if (x) {
+ y = 0;
+ } else {
+ return y;
+ }
+ // Propagated type is [int] here: correct.
+ return y; // marker
+}''',
+ null,
+ typeProvider.intType);
+ }
+
+ void test_mutatedOutsideScope() {
+ // https://code.google.com/p/dart/issues/detail?id=22732
+ Source source = addSource(r'''
+class Base {
+}
+
+class Derived extends Base {
+ get y => null;
+}
+
+class C {
+ void f() {
+ Base x = null;
+ if (x is Derived) {
+ print(x.y); // BAD
+ }
+ x = null;
+ }
+}
+
+void g() {
+ Base x = null;
+ if (x is Derived) {
+ print(x.y); // GOOD
+ }
+ x = null;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ }
+
+ void test_objectAccessInference_disabled_for_library_prefix() {
+ String name = 'hashCode';
+ addNamedSource(
+ '/helper.dart',
+ '''
+library helper;
+dynamic get $name => 42;
+''');
+ String code = '''
+import 'helper.dart' as helper;
+main() {
+ helper.$name; // marker
+}''';
+
+ SimpleIdentifier id = _findMarkedIdentifier(code, "; // marker");
+ PrefixedIdentifier prefixedId = id.parent;
+ expect(id.staticType, typeProvider.dynamicType);
+ expect(prefixedId.staticType, typeProvider.dynamicType);
+ }
+
+ void test_objectAccessInference_disabled_for_local_getter() {
+ String name = 'hashCode';
+ String code = '''
+dynamic get $name => null;
+main() {
+ $name; // marker
+}''';
+
+ SimpleIdentifier getter = _findMarkedIdentifier(code, "; // marker");
+ expect(getter.staticType, typeProvider.dynamicType);
+ }
+
+ void test_objectAccessInference_enabled_for_cascades() {
+ String name = 'hashCode';
+ String code = '''
+main() {
+ dynamic obj;
+ obj..$name..$name; // marker
+}''';
+ PropertyAccess access = _findMarkedIdentifier(code, "; // marker").parent;
+ expect(access.staticType, typeProvider.dynamicType);
+ expect(access.realTarget.staticType, typeProvider.dynamicType);
+ }
+
+ void test_objectMethodInference_disabled_for_library_prefix() {
+ String name = 'toString';
+ addNamedSource(
+ '/helper.dart',
+ '''
+library helper;
+dynamic $name = (int x) => x + 42');
+''');
+ String code = '''
+import 'helper.dart' as helper;
+main() {
+ helper.$name(); // marker
+}''';
+ SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
+ MethodInvocation methodInvoke = methodName.parent;
+ expect(methodName.staticType, null, reason: 'library prefix has no type');
+ expect(methodInvoke.staticType, typeProvider.dynamicType);
+ }
+
+ void test_objectMethodInference_disabled_for_local_function() {
+ String name = 'toString';
+ String code = '''
+main() {
+ dynamic $name = () => null;
+ $name(); // marker
+}''';
+ SimpleIdentifier identifier = _findMarkedIdentifier(code, "$name = ");
+ expect(identifier.staticType, typeProvider.dynamicType);
+
+ SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
+ MethodInvocation methodInvoke = methodName.parent;
+ expect(methodName.staticType, typeProvider.dynamicType);
+ expect(methodInvoke.staticType, typeProvider.dynamicType);
+ }
+
+ void test_objectMethodInference_enabled_for_cascades() {
+ String name = 'toString';
+ String code = '''
+main() {
+ dynamic obj;
+ obj..$name()..$name(); // marker
+}''';
+ SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
+ MethodInvocation methodInvoke = methodName.parent;
+
+ expect(methodInvoke.staticType, typeProvider.dynamicType);
+ expect(methodInvoke.realTarget.staticType, typeProvider.dynamicType);
+ }
+
+ void test_objectMethodOnDynamicExpression_doubleEquals() {
+ // https://code.google.com/p/dart/issues/detail?id=20342
+ //
+ // This was not actually part of Issue 20342, since the spec specifies a
+ // static type of [bool] for [==] comparison and the implementation
+ // was already consistent with the spec there. But, it's another
+ // [Object] method, so it's included here.
+ _assertTypeOfMarkedExpression(
+ r'''
+f1(x) {
+ var v = (x == x);
+ return v; // marker
+}''',
+ null,
+ typeProvider.boolType);
+ }
+
+ void test_objectMethodOnDynamicExpression_hashCode() {
+ // https://code.google.com/p/dart/issues/detail?id=20342
+ _assertTypeOfMarkedExpression(
+ r'''
+f1(x) {
+ var v = x.hashCode;
+ return v; // marker
+}''',
+ null,
+ typeProvider.intType);
+ }
+
+ void test_objectMethodOnDynamicExpression_runtimeType() {
+ // https://code.google.com/p/dart/issues/detail?id=20342
+ _assertTypeOfMarkedExpression(
+ r'''
+f1(x) {
+ var v = x.runtimeType;
+ return v; // marker
+}''',
+ null,
+ typeProvider.typeType);
+ }
+
+ void test_objectMethodOnDynamicExpression_toString() {
+ // https://code.google.com/p/dart/issues/detail?id=20342
+ _assertTypeOfMarkedExpression(
+ r'''
+f1(x) {
+ var v = x.toString();
+ return v; // marker
+}''',
+ null,
+ typeProvider.stringType);
+ }
+
+ void test_propagatedReturnType_localFunction() {
+ String code = r'''
+main() {
+ f() => 42;
+ var v = f();
+}''';
+ _assertPropagatedAssignedType(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_query() {
+ Source source = addSource(r'''
+import 'dart:html';
+
+main() {
+ var v1 = query('a');
+ var v2 = query('A');
+ var v3 = query('body:active');
+ var v4 = query('button[foo="bar"]');
+ var v5 = query('div.class');
+ var v6 = query('input#id');
+ var v7 = query('select#id');
+ // invocation of method
+ var m1 = document.query('div');
+ // unsupported currently
+ var b1 = query('noSuchTag');
+ var b2 = query('DART_EDITOR_NO_SUCH_TYPE');
+ var b3 = query('body div');
+ return [v1, v2, v3, v4, v5, v6, v7, m1, b1, b2, b3];
+}''');
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ FunctionDeclaration main = unit.declarations[0] as FunctionDeclaration;
+ BlockFunctionBody body = main.functionExpression.body as BlockFunctionBody;
+ ReturnStatement statement = body.block.statements[11] as ReturnStatement;
+ NodeList<Expression> elements =
+ (statement.expression as ListLiteral).elements;
+ expect(elements[0].propagatedType.name, "AnchorElement");
+ expect(elements[1].propagatedType.name, "AnchorElement");
+ expect(elements[2].propagatedType.name, "BodyElement");
+ expect(elements[3].propagatedType.name, "ButtonElement");
+ expect(elements[4].propagatedType.name, "DivElement");
+ expect(elements[5].propagatedType.name, "InputElement");
+ expect(elements[6].propagatedType.name, "SelectElement");
+ expect(elements[7].propagatedType.name, "DivElement");
+ expect(elements[8].propagatedType.name, "Element");
+ expect(elements[9].propagatedType.name, "Element");
+ expect(elements[10].propagatedType.name, "Element");
+ }
+}
+
+@reflectiveTest
+class TypeProviderImplTest extends EngineTestCase {
+ void test_creation() {
+ //
+ // Create a mock library element with the types expected to be in dart:core.
+ // We cannot use either ElementFactory or TestTypeProvider (which uses
+ // ElementFactory) because we side-effect the elements in ways that would
+ // break other tests.
+ //
+ InterfaceType objectType = _classElement("Object", null).type;
+ InterfaceType boolType = _classElement("bool", objectType).type;
+ InterfaceType numType = _classElement("num", objectType).type;
+ InterfaceType doubleType = _classElement("double", numType).type;
+ InterfaceType functionType = _classElement("Function", objectType).type;
+ InterfaceType futureType = _classElement("Future", objectType, ["T"]).type;
+ InterfaceType intType = _classElement("int", numType).type;
+ InterfaceType iterableType =
+ _classElement("Iterable", objectType, ["T"]).type;
+ InterfaceType listType = _classElement("List", objectType, ["E"]).type;
+ InterfaceType mapType = _classElement("Map", objectType, ["K", "V"]).type;
+ InterfaceType stackTraceType = _classElement("StackTrace", objectType).type;
+ InterfaceType streamType = _classElement("Stream", objectType, ["T"]).type;
+ InterfaceType stringType = _classElement("String", objectType).type;
+ InterfaceType symbolType = _classElement("Symbol", objectType).type;
+ InterfaceType typeType = _classElement("Type", objectType).type;
+ CompilationUnitElementImpl coreUnit =
+ new CompilationUnitElementImpl("core.dart");
+ coreUnit.types = <ClassElement>[
+ boolType.element,
+ doubleType.element,
+ functionType.element,
+ intType.element,
+ iterableType.element,
+ listType.element,
+ mapType.element,
+ objectType.element,
+ stackTraceType.element,
+ stringType.element,
+ symbolType.element,
+ typeType.element
+ ];
+ CompilationUnitElementImpl asyncUnit =
+ new CompilationUnitElementImpl("async.dart");
+ asyncUnit.types = <ClassElement>[futureType.element, streamType.element];
+ AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+ LibraryElementImpl coreLibrary = new LibraryElementImpl.forNode(
+ context, AstFactory.libraryIdentifier2(["dart.core"]));
+ coreLibrary.definingCompilationUnit = coreUnit;
+ LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
+ context, AstFactory.libraryIdentifier2(["dart.async"]));
+ asyncLibrary.definingCompilationUnit = asyncUnit;
+ //
+ // Create a type provider and ensure that it can return the expected types.
+ //
+ TypeProviderImpl provider = new TypeProviderImpl(coreLibrary, asyncLibrary);
+ expect(provider.boolType, same(boolType));
+ expect(provider.bottomType, isNotNull);
+ expect(provider.doubleType, same(doubleType));
+ expect(provider.dynamicType, isNotNull);
+ expect(provider.functionType, same(functionType));
+ expect(provider.futureType, same(futureType));
+ expect(provider.intType, same(intType));
+ expect(provider.listType, same(listType));
+ expect(provider.mapType, same(mapType));
+ expect(provider.objectType, same(objectType));
+ expect(provider.stackTraceType, same(stackTraceType));
+ expect(provider.stringType, same(stringType));
+ expect(provider.symbolType, same(symbolType));
+ expect(provider.typeType, same(typeType));
+ }
+
+ ClassElement _classElement(String typeName, InterfaceType superclassType,
+ [List<String> parameterNames]) {
+ ClassElementImpl element =
+ new ClassElementImpl.forNode(AstFactory.identifier3(typeName));
+ element.supertype = superclassType;
+ InterfaceTypeImpl type = new InterfaceTypeImpl(element);
+ element.type = type;
+ if (parameterNames != null) {
+ int count = parameterNames.length;
+ if (count > 0) {
+ List<TypeParameterElementImpl> typeParameters =
+ new List<TypeParameterElementImpl>(count);
+ List<TypeParameterTypeImpl> typeArguments =
+ new List<TypeParameterTypeImpl>(count);
+ for (int i = 0; i < count; i++) {
+ TypeParameterElementImpl typeParameter =
+ new TypeParameterElementImpl.forNode(
+ AstFactory.identifier3(parameterNames[i]));
+ typeParameters[i] = typeParameter;
+ typeArguments[i] = new TypeParameterTypeImpl(typeParameter);
+ typeParameter.type = typeArguments[i];
+ }
+ element.typeParameters = typeParameters;
+ type.typeArguments = typeArguments;
+ }
+ }
+ return element;
+ }
+}
+
+@reflectiveTest
+class TypeResolverVisitorTest extends EngineTestCase {
+ /**
+ * The error listener to which errors will be reported.
+ */
+ GatheringErrorListener _listener;
+
+ /**
+ * The object representing the information about the library in which the types are being
+ * resolved.
+ */
+ Library _library;
+
+ /**
+ * The type provider used to access the types.
+ */
+ TestTypeProvider _typeProvider;
+
+ /**
+ * The visitor used to resolve types needed to form the type hierarchy.
+ */
+ TypeResolverVisitor _visitor;
+
+ void fail_visitConstructorDeclaration() {
+ fail("Not yet tested");
+ _listener.assertNoErrors();
+ }
+
+ void fail_visitFunctionTypeAlias() {
+ fail("Not yet tested");
+ _listener.assertNoErrors();
+ }
+
+ void fail_visitVariableDeclaration() {
+ fail("Not yet tested");
+ ClassElement type = ElementFactory.classElement2("A");
+ VariableDeclaration node = AstFactory.variableDeclaration("a");
+ AstFactory.variableDeclarationList(null, AstFactory.typeName(type), [node]);
+ //resolve(node);
+ expect(node.name.staticType, same(type.type));
+ _listener.assertNoErrors();
+ }
+
+ @override
+ void setUp() {
+ _listener = new GatheringErrorListener();
+ InternalAnalysisContext context = AnalysisContextFactory.contextWithCore();
+ Source librarySource =
+ new FileBasedSource(FileUtilities2.createFile("/lib.dart"));
+ _library = new Library(context, _listener, librarySource);
+ LibraryElementImpl element = new LibraryElementImpl.forNode(
+ context, AstFactory.libraryIdentifier2(["lib"]));
+ element.definingCompilationUnit =
+ new CompilationUnitElementImpl("lib.dart");
+ _library.libraryElement = element;
+ _typeProvider = new TestTypeProvider();
+ _visitor = new TypeResolverVisitor(_library.libraryElement, librarySource,
+ _typeProvider, _library.errorListener,
+ nameScope: _library.libraryScope);
+ }
+
+ void test_visitCatchClause_exception() {
+ // catch (e)
+ CatchClause clause = AstFactory.catchClause("e");
+ SimpleIdentifier exceptionParameter = clause.exceptionParameter;
+ exceptionParameter.staticElement =
+ new LocalVariableElementImpl.forNode(exceptionParameter);
+ _resolveCatchClause(clause, _typeProvider.dynamicType, null);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitCatchClause_exception_stackTrace() {
+ // catch (e, s)
+ CatchClause clause = AstFactory.catchClause2("e", "s");
+ SimpleIdentifier exceptionParameter = clause.exceptionParameter;
+ exceptionParameter.staticElement =
+ new LocalVariableElementImpl.forNode(exceptionParameter);
+ SimpleIdentifier stackTraceParameter = clause.stackTraceParameter;
+ stackTraceParameter.staticElement =
+ new LocalVariableElementImpl.forNode(stackTraceParameter);
+ _resolveCatchClause(
+ clause, _typeProvider.dynamicType, _typeProvider.stackTraceType);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitCatchClause_on_exception() {
+ // on E catch (e)
+ ClassElement exceptionElement = ElementFactory.classElement2("E");
+ TypeName exceptionType = AstFactory.typeName(exceptionElement);
+ CatchClause clause = AstFactory.catchClause4(exceptionType, "e");
+ SimpleIdentifier exceptionParameter = clause.exceptionParameter;
+ exceptionParameter.staticElement =
+ new LocalVariableElementImpl.forNode(exceptionParameter);
+ _resolveCatchClause(
+ clause, exceptionElement.type, null, [exceptionElement]);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitCatchClause_on_exception_stackTrace() {
+ // on E catch (e, s)
+ ClassElement exceptionElement = ElementFactory.classElement2("E");
+ TypeName exceptionType = AstFactory.typeName(exceptionElement);
+ (exceptionType.name as SimpleIdentifier).staticElement = exceptionElement;
+ CatchClause clause = AstFactory.catchClause5(exceptionType, "e", "s");
+ SimpleIdentifier exceptionParameter = clause.exceptionParameter;
+ exceptionParameter.staticElement =
+ new LocalVariableElementImpl.forNode(exceptionParameter);
+ SimpleIdentifier stackTraceParameter = clause.stackTraceParameter;
+ stackTraceParameter.staticElement =
+ new LocalVariableElementImpl.forNode(stackTraceParameter);
+ _resolveCatchClause(clause, exceptionElement.type,
+ _typeProvider.stackTraceType, [exceptionElement]);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitClassDeclaration() {
+ // class A extends B with C implements D {}
+ // class B {}
+ // class C {}
+ // class D {}
+ ClassElement elementA = ElementFactory.classElement2("A");
+ ClassElement elementB = ElementFactory.classElement2("B");
+ ClassElement elementC = ElementFactory.classElement2("C");
+ ClassElement elementD = ElementFactory.classElement2("D");
+ ExtendsClause extendsClause =
+ AstFactory.extendsClause(AstFactory.typeName(elementB));
+ WithClause withClause =
+ AstFactory.withClause([AstFactory.typeName(elementC)]);
+ ImplementsClause implementsClause =
+ AstFactory.implementsClause([AstFactory.typeName(elementD)]);
+ ClassDeclaration declaration = AstFactory.classDeclaration(
+ null, "A", null, extendsClause, withClause, implementsClause);
+ declaration.name.staticElement = elementA;
+ _resolveNode(declaration, [elementA, elementB, elementC, elementD]);
+ expect(elementA.supertype, same(elementB.type));
+ List<InterfaceType> mixins = elementA.mixins;
+ expect(mixins, hasLength(1));
+ expect(mixins[0], same(elementC.type));
+ List<InterfaceType> interfaces = elementA.interfaces;
+ expect(interfaces, hasLength(1));
+ expect(interfaces[0], same(elementD.type));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitClassDeclaration_instanceMemberCollidesWithClass() {
+ // class A {}
+ // class B extends A {
+ // void A() {}
+ // }
+ ClassElementImpl elementA = ElementFactory.classElement2("A");
+ ClassElementImpl elementB = ElementFactory.classElement2("B");
+ elementB.methods = <MethodElement>[
+ ElementFactory.methodElement("A", VoidTypeImpl.instance)
+ ];
+ ExtendsClause extendsClause =
+ AstFactory.extendsClause(AstFactory.typeName(elementA));
+ ClassDeclaration declaration =
+ AstFactory.classDeclaration(null, "B", null, extendsClause, null, null);
+ declaration.name.staticElement = elementB;
+ _resolveNode(declaration, [elementA, elementB]);
+ expect(elementB.supertype, same(elementA.type));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitClassTypeAlias() {
+ // class A = B with C implements D;
+ ClassElement elementA = ElementFactory.classElement2("A");
+ ClassElement elementB = ElementFactory.classElement2("B");
+ ClassElement elementC = ElementFactory.classElement2("C");
+ ClassElement elementD = ElementFactory.classElement2("D");
+ WithClause withClause =
+ AstFactory.withClause([AstFactory.typeName(elementC)]);
+ ImplementsClause implementsClause =
+ AstFactory.implementsClause([AstFactory.typeName(elementD)]);
+ ClassTypeAlias alias = AstFactory.classTypeAlias("A", null, null,
+ AstFactory.typeName(elementB), withClause, implementsClause);
+ alias.name.staticElement = elementA;
+ _resolveNode(alias, [elementA, elementB, elementC, elementD]);
+ expect(elementA.supertype, same(elementB.type));
+ List<InterfaceType> mixins = elementA.mixins;
+ expect(mixins, hasLength(1));
+ expect(mixins[0], same(elementC.type));
+ List<InterfaceType> interfaces = elementA.interfaces;
+ expect(interfaces, hasLength(1));
+ expect(interfaces[0], same(elementD.type));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitClassTypeAlias_constructorWithOptionalParams_ignored() {
+ // class T {}
+ // class B {
+ // B.c1();
+ // B.c2([T a0]);
+ // B.c3({T a0});
+ // }
+ // class M {}
+ // class C = B with M
+ ClassElement classT = ElementFactory.classElement2('T', []);
+ ClassElementImpl classB = ElementFactory.classElement2('B', []);
+ ConstructorElementImpl constructorBc1 =
+ ElementFactory.constructorElement2(classB, 'c1', []);
+ ConstructorElementImpl constructorBc2 =
+ ElementFactory.constructorElement2(classB, 'c2', [classT.type]);
+ (constructorBc2.parameters[0] as ParameterElementImpl).parameterKind =
+ ParameterKind.POSITIONAL;
+ ConstructorElementImpl constructorBc3 =
+ ElementFactory.constructorElement2(classB, 'c3', [classT.type]);
+ (constructorBc3.parameters[0] as ParameterElementImpl).parameterKind =
+ ParameterKind.NAMED;
+ classB.constructors = [constructorBc1, constructorBc2, constructorBc3];
+ ClassElement classM = ElementFactory.classElement2('M', []);
+ WithClause withClause =
+ AstFactory.withClause([AstFactory.typeName(classM, [])]);
+ ClassElement classC = ElementFactory.classTypeAlias2('C', []);
+ ClassTypeAlias alias = AstFactory.classTypeAlias(
+ 'C', null, null, AstFactory.typeName(classB, []), withClause, null);
+ alias.name.staticElement = classC;
+ _resolveNode(alias, [classT, classB, classM, classC]);
+ expect(classC.constructors, hasLength(1));
+ ConstructorElement constructor = classC.constructors[0];
+ expect(constructor.isFactory, isFalse);
+ expect(constructor.isSynthetic, isTrue);
+ expect(constructor.name, 'c1');
+ expect(constructor.functions, hasLength(0));
+ expect(constructor.labels, hasLength(0));
+ expect(constructor.localVariables, hasLength(0));
+ expect(constructor.parameters, isEmpty);
+ }
+
+ void test_visitClassTypeAlias_constructorWithParams() {
+ // class T {}
+ // class B {
+ // B(T a0);
+ // }
+ // class M {}
+ // class C = B with M
+ ClassElement classT = ElementFactory.classElement2('T', []);
+ ClassElementImpl classB = ElementFactory.classElement2('B', []);
+ ConstructorElementImpl constructorB =
+ ElementFactory.constructorElement2(classB, '', [classT.type]);
+ classB.constructors = [constructorB];
+ ClassElement classM = ElementFactory.classElement2('M', []);
+ WithClause withClause =
+ AstFactory.withClause([AstFactory.typeName(classM, [])]);
+ ClassElement classC = ElementFactory.classTypeAlias2('C', []);
+ ClassTypeAlias alias = AstFactory.classTypeAlias(
+ 'C', null, null, AstFactory.typeName(classB, []), withClause, null);
+ alias.name.staticElement = classC;
+ _resolveNode(alias, [classT, classB, classM, classC]);
+ expect(classC.constructors, hasLength(1));
+ ConstructorElement constructor = classC.constructors[0];
+ expect(constructor.isFactory, isFalse);
+ expect(constructor.isSynthetic, isTrue);
+ expect(constructor.name, '');
+ expect(constructor.functions, hasLength(0));
+ expect(constructor.labels, hasLength(0));
+ expect(constructor.localVariables, hasLength(0));
+ expect(constructor.parameters, hasLength(1));
+ expect(constructor.parameters[0].type, equals(classT.type));
+ expect(constructor.parameters[0].name,
+ equals(constructorB.parameters[0].name));
+ }
+
+ void test_visitClassTypeAlias_defaultConstructor() {
+ // class B {}
+ // class M {}
+ // class C = B with M
+ ClassElementImpl classB = ElementFactory.classElement2('B', []);
+ ConstructorElementImpl constructorB =
+ ElementFactory.constructorElement2(classB, '', []);
+ constructorB.setModifier(Modifier.SYNTHETIC, true);
+ classB.constructors = [constructorB];
+ ClassElement classM = ElementFactory.classElement2('M', []);
+ WithClause withClause =
+ AstFactory.withClause([AstFactory.typeName(classM, [])]);
+ ClassElement classC = ElementFactory.classTypeAlias2('C', []);
+ ClassTypeAlias alias = AstFactory.classTypeAlias(
+ 'C', null, null, AstFactory.typeName(classB, []), withClause, null);
+ alias.name.staticElement = classC;
+ _resolveNode(alias, [classB, classM, classC]);
+ expect(classC.constructors, hasLength(1));
+ ConstructorElement constructor = classC.constructors[0];
+ expect(constructor.isFactory, isFalse);
+ expect(constructor.isSynthetic, isTrue);
+ expect(constructor.name, '');
+ expect(constructor.functions, hasLength(0));
+ expect(constructor.labels, hasLength(0));
+ expect(constructor.localVariables, hasLength(0));
+ expect(constructor.parameters, isEmpty);
+ }
+
+ void test_visitFieldFormalParameter_functionType() {
+ InterfaceType intType = _typeProvider.intType;
+ TypeName intTypeName = AstFactory.typeName4("int");
+ String innerParameterName = "a";
+ SimpleFormalParameter parameter =
+ AstFactory.simpleFormalParameter3(innerParameterName);
+ parameter.identifier.staticElement =
+ ElementFactory.requiredParameter(innerParameterName);
+ String outerParameterName = "p";
+ FormalParameter node = AstFactory.fieldFormalParameter(null, intTypeName,
+ outerParameterName, AstFactory.formalParameterList([parameter]));
+ node.identifier.staticElement =
+ ElementFactory.requiredParameter(outerParameterName);
+ DartType parameterType = _resolveFormalParameter(node, [intType.element]);
+ EngineTestCase.assertInstanceOf(
+ (obj) => obj is FunctionType, FunctionType, parameterType);
+ FunctionType functionType = parameterType as FunctionType;
+ expect(functionType.returnType, same(intType));
+ expect(functionType.parameters, hasLength(1));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFieldFormalParameter_noType() {
+ String parameterName = "p";
+ FormalParameter node =
+ AstFactory.fieldFormalParameter(Keyword.VAR, null, parameterName);
+ node.identifier.staticElement =
+ ElementFactory.requiredParameter(parameterName);
+ expect(_resolveFormalParameter(node), same(_typeProvider.dynamicType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFieldFormalParameter_type() {
+ InterfaceType intType = _typeProvider.intType;
+ TypeName intTypeName = AstFactory.typeName4("int");
+ String parameterName = "p";
+ FormalParameter node =
+ AstFactory.fieldFormalParameter(null, intTypeName, parameterName);
+ node.identifier.staticElement =
+ ElementFactory.requiredParameter(parameterName);
+ expect(_resolveFormalParameter(node, [intType.element]), same(intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionDeclaration() {
+ // R f(P p) {}
+ // class R {}
+ // class P {}
+ ClassElement elementR = ElementFactory.classElement2('R');
+ ClassElement elementP = ElementFactory.classElement2('P');
+ FunctionElement elementF = ElementFactory.functionElement('f');
+ FunctionDeclaration declaration = AstFactory.functionDeclaration(
+ AstFactory.typeName4('R'),
+ null,
+ 'f',
+ AstFactory.functionExpression2(
+ AstFactory.formalParameterList([
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('P'), 'p')
+ ]),
+ null));
+ declaration.name.staticElement = elementF;
+ _resolveNode(declaration, [elementR, elementP]);
+ expect(declaration.returnType.type, elementR.type);
+ SimpleFormalParameter parameter =
+ declaration.functionExpression.parameters.parameters[0];
+ expect(parameter.type.type, elementP.type);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionDeclaration_typeParameter() {
+ // E f<E>(E e) {}
+ TypeParameterElement elementE = ElementFactory.typeParameterElement('E');
+ FunctionElementImpl elementF = ElementFactory.functionElement('f');
+ elementF.typeParameters = <TypeParameterElement>[elementE];
+ FunctionDeclaration declaration = AstFactory.functionDeclaration(
+ AstFactory.typeName4('E'),
+ null,
+ 'f',
+ AstFactory.functionExpression2(
+ AstFactory.formalParameterList([
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('E'), 'e')
+ ]),
+ null));
+ declaration.name.staticElement = elementF;
+ _resolveNode(declaration, []);
+ expect(declaration.returnType.type, elementE.type);
+ SimpleFormalParameter parameter =
+ declaration.functionExpression.parameters.parameters[0];
+ expect(parameter.type.type, elementE.type);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionTypedFormalParameter() {
+ // R f(R g(P p)) {}
+ // class R {}
+ // class P {}
+ ClassElement elementR = ElementFactory.classElement2('R');
+ ClassElement elementP = ElementFactory.classElement2('P');
+ FunctionElement elementF = ElementFactory.functionElement('f');
+ ParameterElementImpl requiredParameter =
+ ElementFactory.requiredParameter('p');
+ FunctionTypedFormalParameter parameterDeclaration = AstFactory
+ .functionTypedFormalParameter(AstFactory.typeName4('R'), 'g', [
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('P'), 'p')
+ ]);
+ parameterDeclaration.identifier.staticElement = requiredParameter;
+ FunctionDeclaration declaration = AstFactory.functionDeclaration(
+ AstFactory.typeName4('R'),
+ null,
+ 'f',
+ AstFactory.functionExpression2(
+ AstFactory.formalParameterList([parameterDeclaration]), null));
+ declaration.name.staticElement = elementF;
+ _resolveNode(declaration, [elementR, elementP]);
+ expect(declaration.returnType.type, elementR.type);
+ FunctionTypedFormalParameter parameter =
+ declaration.functionExpression.parameters.parameters[0];
+ expect(parameter.returnType.type, elementR.type);
+ SimpleFormalParameter innerParameter = parameter.parameters.parameters[0];
+ expect(innerParameter.type.type, elementP.type);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitFunctionTypedFormalParameter_typeParameter() {
+ // R f(R g<E>(E e)) {}
+ // class R {}
+ ClassElement elementR = ElementFactory.classElement2('R');
+ TypeParameterElement elementE = ElementFactory.typeParameterElement('E');
+ FunctionElement elementF = ElementFactory.functionElement('f');
+ ParameterElementImpl requiredParameter =
+ ElementFactory.requiredParameter('g');
+ requiredParameter.typeParameters = <TypeParameterElement>[elementE];
+ FunctionTypedFormalParameter parameterDeclaration = AstFactory
+ .functionTypedFormalParameter(AstFactory.typeName4('R'), 'g', [
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('E'), 'e')
+ ]);
+ parameterDeclaration.identifier.staticElement = requiredParameter;
+ FunctionDeclaration declaration = AstFactory.functionDeclaration(
+ AstFactory.typeName4('R'),
+ null,
+ 'f',
+ AstFactory.functionExpression2(
+ AstFactory.formalParameterList([parameterDeclaration]), null));
+ declaration.name.staticElement = elementF;
+ _resolveNode(declaration, [elementR]);
+ expect(declaration.returnType.type, elementR.type);
+ FunctionTypedFormalParameter parameter =
+ declaration.functionExpression.parameters.parameters[0];
+ expect(parameter.returnType.type, elementR.type);
+ SimpleFormalParameter innerParameter = parameter.parameters.parameters[0];
+ expect(innerParameter.type.type, elementE.type);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitMethodDeclaration() {
+ // class A {
+ // R m(P p) {}
+ // }
+ // class R {}
+ // class P {}
+ ClassElementImpl elementA = ElementFactory.classElement2('A');
+ ClassElement elementR = ElementFactory.classElement2('R');
+ ClassElement elementP = ElementFactory.classElement2('P');
+ MethodElement elementM = ElementFactory.methodElement('m', null);
+ elementA.methods = <MethodElement>[elementM];
+ MethodDeclaration declaration = AstFactory.methodDeclaration(
+ null,
+ AstFactory.typeName4('R'),
+ null,
+ null,
+ AstFactory.identifier3('m'),
+ AstFactory.formalParameterList([
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('P'), 'p')
+ ]));
+ declaration.name.staticElement = elementM;
+ _resolveNode(declaration, [elementA, elementR, elementP]);
+ expect(declaration.returnType.type, elementR.type);
+ SimpleFormalParameter parameter = declaration.parameters.parameters[0];
+ expect(parameter.type.type, elementP.type);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitMethodDeclaration_typeParameter() {
+ // class A {
+ // E m<E>(E e) {}
+ // }
+ ClassElementImpl elementA = ElementFactory.classElement2('A');
+ TypeParameterElement elementE = ElementFactory.typeParameterElement('E');
+ MethodElementImpl elementM = ElementFactory.methodElement('m', null);
+ elementM.typeParameters = <TypeParameterElement>[elementE];
+ elementA.methods = <MethodElement>[elementM];
+ MethodDeclaration declaration = AstFactory.methodDeclaration(
+ null,
+ AstFactory.typeName4('E'),
+ null,
+ null,
+ AstFactory.identifier3('m'),
+ AstFactory.formalParameterList([
+ AstFactory.simpleFormalParameter4(AstFactory.typeName4('E'), 'e')
+ ]));
+ declaration.name.staticElement = elementM;
+ _resolveNode(declaration, [elementA]);
+ expect(declaration.returnType.type, elementE.type);
+ SimpleFormalParameter parameter = declaration.parameters.parameters[0];
+ expect(parameter.type.type, elementE.type);
+ _listener.assertNoErrors();
+ }
+
+ void test_visitSimpleFormalParameter_noType() {
+ // p
+ FormalParameter node = AstFactory.simpleFormalParameter3("p");
+ node.identifier.staticElement =
+ new ParameterElementImpl.forNode(AstFactory.identifier3("p"));
+ expect(_resolveFormalParameter(node), same(_typeProvider.dynamicType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitSimpleFormalParameter_type() {
+ // int p
+ InterfaceType intType = _typeProvider.intType;
+ ClassElement intElement = intType.element;
+ FormalParameter node =
+ AstFactory.simpleFormalParameter4(AstFactory.typeName(intElement), "p");
+ SimpleIdentifier identifier = node.identifier;
+ ParameterElementImpl element = new ParameterElementImpl.forNode(identifier);
+ identifier.staticElement = element;
+ expect(_resolveFormalParameter(node, [intElement]), same(intType));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitTypeName_noParameters_noArguments() {
+ ClassElement classA = ElementFactory.classElement2("A");
+ TypeName typeName = AstFactory.typeName(classA);
+ typeName.type = null;
+ _resolveNode(typeName, [classA]);
+ expect(typeName.type, same(classA.type));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitTypeName_parameters_arguments() {
+ ClassElement classA = ElementFactory.classElement2("A", ["E"]);
+ ClassElement classB = ElementFactory.classElement2("B");
+ TypeName typeName =
+ AstFactory.typeName(classA, [AstFactory.typeName(classB)]);
+ typeName.type = null;
+ _resolveNode(typeName, [classA, classB]);
+ InterfaceType resultType = typeName.type as InterfaceType;
+ expect(resultType.element, same(classA));
+ List<DartType> resultArguments = resultType.typeArguments;
+ expect(resultArguments, hasLength(1));
+ expect(resultArguments[0], same(classB.type));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitTypeName_parameters_noArguments() {
+ ClassElement classA = ElementFactory.classElement2("A", ["E"]);
+ TypeName typeName = AstFactory.typeName(classA);
+ typeName.type = null;
+ _resolveNode(typeName, [classA]);
+ InterfaceType resultType = typeName.type as InterfaceType;
+ expect(resultType.element, same(classA));
+ List<DartType> resultArguments = resultType.typeArguments;
+ expect(resultArguments, hasLength(1));
+ expect(resultArguments[0], same(DynamicTypeImpl.instance));
+ _listener.assertNoErrors();
+ }
+
+ void test_visitTypeName_void() {
+ ClassElement classA = ElementFactory.classElement2("A");
+ TypeName typeName = AstFactory.typeName4("void");
+ _resolveNode(typeName, [classA]);
+ expect(typeName.type, same(VoidTypeImpl.instance));
+ _listener.assertNoErrors();
+ }
+
+ /**
+ * Analyze the given catch clause and assert that the types of the parameters have been set to the
+ * given types. The types can be null if the catch clause does not have the corresponding
+ * parameter.
+ *
+ * @param node the catch clause to be analyzed
+ * @param exceptionType the expected type of the exception parameter
+ * @param stackTraceType the expected type of the stack trace parameter
+ * @param definedElements the elements that are to be defined in the scope in which the element is
+ * being resolved
+ */
+ void _resolveCatchClause(
+ CatchClause node, DartType exceptionType, InterfaceType stackTraceType,
+ [List<Element> definedElements]) {
+ _resolveNode(node, definedElements);
+ SimpleIdentifier exceptionParameter = node.exceptionParameter;
+ if (exceptionParameter != null) {
+ expect(exceptionParameter.staticType, same(exceptionType));
+ }
+ SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
+ if (stackTraceParameter != null) {
+ expect(stackTraceParameter.staticType, same(stackTraceType));
+ }
+ }
+
+ /**
+ * Return the type associated with the given parameter after the static type analyzer has computed
+ * a type for it.
+ *
+ * @param node the parameter with which the type is associated
+ * @param definedElements the elements that are to be defined in the scope in which the element is
+ * being resolved
+ * @return the type associated with the parameter
+ */
+ DartType _resolveFormalParameter(FormalParameter node,
+ [List<Element> definedElements]) {
+ _resolveNode(node, definedElements);
+ return (node.identifier.staticElement as ParameterElement).type;
+ }
+
+ /**
+ * 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]) {
+ if (definedElements != null) {
+ for (Element element in definedElements) {
+ _library.libraryScope.define(element);
+ }
+ }
+ node.accept(_visitor);
+ }
+}
+
+class _AnalysisContextFactory_initContextWithCore
+ extends DirectoryBasedDartSdk {
+ _AnalysisContextFactory_initContextWithCore(JavaFile arg0) : super(arg0);
+
+ @override
+ LibraryMap initialLibraryMap(bool useDart2jsPaths) {
+ LibraryMap map = new LibraryMap();
+ _addLibrary(map, DartSdk.DART_ASYNC, false, "async.dart");
+ _addLibrary(map, DartSdk.DART_CORE, false, "core.dart");
+ _addLibrary(map, DartSdk.DART_HTML, false, "html_dartium.dart");
+ _addLibrary(map, AnalysisContextFactory._DART_MATH, false, "math.dart");
+ _addLibrary(map, AnalysisContextFactory._DART_INTERCEPTORS, true,
+ "_interceptors.dart");
+ _addLibrary(
+ map, AnalysisContextFactory._DART_JS_HELPER, true, "_js_helper.dart");
+ return map;
+ }
+
+ void _addLibrary(LibraryMap map, String uri, bool isInternal, String path) {
+ SdkLibraryImpl library = new SdkLibraryImpl(uri);
+ if (isInternal) {
+ library.category = "Internal";
+ }
+ library.path = path;
+ map.setLibrary(uri, library);
+ }
+}
+
+class _SimpleResolverTest_localVariable_types_invoked
+ extends RecursiveAstVisitor<Object> {
+ final SimpleResolverTest test;
+
+ List<bool> found;
+
+ List<CaughtException> thrownException;
+
+ _SimpleResolverTest_localVariable_types_invoked(
+ this.test, this.found, this.thrownException)
+ : super();
+
+ @override
+ Object visitSimpleIdentifier(SimpleIdentifier node) {
+ if (node.name == "myVar" && node.parent is MethodInvocation) {
+ try {
+ found[0] = true;
+ // check static type
+ DartType staticType = node.staticType;
+ expect(staticType, same(test.typeProvider.dynamicType));
+ // check propagated type
+ FunctionType propagatedType = node.propagatedType as FunctionType;
+ expect(propagatedType.returnType, test.typeProvider.stringType);
+ } on AnalysisException catch (e, stackTrace) {
+ thrownException[0] = new CaughtException(e, stackTrace);
+ }
+ }
+ return null;
+ }
+}
+
+/**
+ * Shared infrastructure for [StaticTypeAnalyzer2Test] and
+ * [StrongModeStaticTypeAnalyzer2Test].
+ */
+class _StaticTypeAnalyzer2TestShared extends ResolverTestCase {
+ String testCode;
+ Source testSource;
+ CompilationUnit testUnit;
+
+ SimpleIdentifier _findIdentifier(String search) {
+ SimpleIdentifier identifier = EngineTestCase.findNode(
+ testUnit, testCode, search, (node) => node is SimpleIdentifier);
+ return identifier;
+ }
+
+ void _resolveTestUnit(String code) {
+ testCode = code;
+ testSource = addSource(testCode);
+ LibraryElement library = resolve2(testSource);
+ assertNoErrors(testSource);
+ verify([testSource]);
+ testUnit = resolveCompilationUnit(testSource, library);
+ }
+}
« no previous file with comments | « packages/analyzer/test/generated/parser_test.dart ('k') | packages/analyzer/test/generated/scanner_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698