| // 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 analyzer.test.generated.resolver_test; |
| |
| import 'dart:async'; |
| import 'dart:collection'; |
| |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:analyzer/dart/ast/standard_ast_factory.dart'; |
| import 'package:analyzer/dart/ast/standard_resolution_map.dart'; |
| import 'package:analyzer/dart/ast/token.dart'; |
| import 'package:analyzer/dart/ast/visitor.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/dart/element/type.dart'; |
| import 'package:analyzer/file_system/memory_file_system.dart'; |
| import 'package:analyzer/src/dart/ast/ast.dart'; |
| import 'package:analyzer/src/dart/element/builder.dart'; |
| import 'package:analyzer/src/dart/element/element.dart'; |
| import 'package:analyzer/src/dart/element/type.dart'; |
| import 'package:analyzer/src/error/codes.dart'; |
| import 'package:analyzer/src/generated/engine.dart'; |
| import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode; |
| import 'package:analyzer/src/generated/resolver.dart'; |
| import 'package:analyzer/src/generated/source_io.dart'; |
| import 'package:analyzer/src/generated/testing/ast_test_factory.dart'; |
| import 'package:analyzer/src/generated/testing/element_factory.dart'; |
| import 'package:analyzer/src/generated/testing/element_search.dart'; |
| import 'package:analyzer/src/generated/testing/test_type_provider.dart'; |
| import 'package:analyzer/src/generated/utilities_dart.dart'; |
| import 'package:analyzer/src/source/source_resource.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import 'analysis_context_factory.dart'; |
| import 'parser_test.dart'; |
| import 'resolver_test_case.dart'; |
| import 'test_support.dart'; |
| |
| main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(AnalysisDeltaTest); |
| defineReflectiveTests(ChangeSetTest); |
| defineReflectiveTests(EnclosedScopeTest); |
| defineReflectiveTests(ErrorResolverTest); |
| defineReflectiveTests(LibraryImportScopeTest); |
| defineReflectiveTests(LibraryScopeTest); |
| defineReflectiveTests(PrefixedNamespaceTest); |
| defineReflectiveTests(ScopeTest); |
| defineReflectiveTests(StrictModeTest); |
| defineReflectiveTests(SubtypeManagerTest); |
| defineReflectiveTests(TypeOverrideManagerTest); |
| defineReflectiveTests(TypePropagationTest); |
| defineReflectiveTests(TypeProviderImplTest); |
| defineReflectiveTests(TypeResolverVisitorTest); |
| }); |
| } |
| |
| /// Wrapper around the test package's `fail` function. |
| /// |
| /// Unlike the test package's `fail` function, this function is not annotated |
| /// with @alwaysThrows, so we can call it at the top of a test method without |
| /// causing the rest of the method to be flagged as dead code. |
| void _fail(String message) { |
| fail(message); |
| } |
| |
| @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.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.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.removedSource(new TestSource()); |
| changeSet |
| .removedContainer(new SourceContainer_ChangeSetTest_test_toString()); |
| expect(changeSet.toString(), isNotNull); |
| } |
| } |
| |
| @reflectiveTest |
| class EnclosedScopeTest extends ResolverTestCase { |
| test_define_duplicate() async { |
| Scope rootScope = new _RootScope(); |
| EnclosedScope scope = new EnclosedScope(rootScope); |
| SimpleIdentifier identifier = AstTestFactory.identifier3('v'); |
| VariableElement element1 = ElementFactory.localVariableElement(identifier); |
| VariableElement element2 = ElementFactory.localVariableElement(identifier); |
| scope.define(element1); |
| scope.define(element2); |
| expect(scope.lookup(identifier, null), same(element1)); |
| } |
| } |
| |
| @reflectiveTest |
| class ErrorResolverTest extends ResolverTestCase { |
| test_breakLabelOnSwitchMember() async { |
| Source source = addSource(r''' |
| class A { |
| void m(int i) { |
| switch (i) { |
| l: case 0: |
| break; |
| case 1: |
| break l; |
| } |
| } |
| }'''); |
| await computeAnalysisResult(source); |
| assertErrors(source, [ResolverErrorCode.BREAK_LABEL_ON_SWITCH_MEMBER]); |
| verify([source]); |
| } |
| |
| test_continueLabelOnSwitch() async { |
| Source source = addSource(r''' |
| class A { |
| void m(int i) { |
| l: switch (i) { |
| case 0: |
| continue l; |
| } |
| } |
| }'''); |
| await computeAnalysisResult(source); |
| assertErrors(source, [ResolverErrorCode.CONTINUE_LABEL_ON_SWITCH]); |
| verify([source]); |
| } |
| |
| test_enclosingElement_invalidLocalFunction() async { |
| String code = r''' |
| class C { |
| C() { |
| int get x => 0; |
| } |
| }'''; |
| Source source = addSource(code); |
| |
| TestAnalysisResult analysisResult = await computeAnalysisResult(source); |
| assertErrors(source, [ParserErrorCode.GETTER_IN_FUNCTION]); |
| |
| CompilationUnitElement unit = analysisResult.unit.element; |
| LibraryElement library = unit.library; |
| expect(library, isNotNull); |
| expect(unit.enclosingElement, same(library)); |
| |
| var types = unit.types; |
| expect(types, hasLength(1)); |
| var type = types[0]; |
| expect(type, isNotNull); |
| |
| var constructors = type.constructors; |
| expect(constructors, hasLength(1)); |
| ConstructorElement constructor = constructors[0]; |
| expect(constructor, isNotNull); |
| |
| FunctionElement x = findElementsByName(analysisResult.unit, 'x').single; |
| expect(x.enclosingElement, constructor); |
| } |
| } |
| |
| /** |
| * Tests for generic method and function resolution that do not use strong mode. |
| */ |
| @reflectiveTest |
| class GenericMethodResolverTest extends StaticTypeAnalyzer2TestShared { |
| test_genericMethod_propagatedType_promotion() async { |
| // Regression test for: |
| // https://github.com/dart-lang/sdk/issues/25340 |
| // |
| // Note, after https://github.com/dart-lang/sdk/issues/25486 the original |
| // strong mode example won't work, as we now compute a static type and |
| // therefore discard the propagated type. |
| // |
| // So this test does not use strong mode. |
| await resolveTestUnit(r''' |
| abstract class Iter { |
| List<S> map<S>(S f(x)); |
| } |
| class C {} |
| C toSpan(dynamic element) { |
| if (element is Iter) { |
| var y = element.map(toSpan); |
| } |
| return null; |
| }'''); |
| expectIdentifierType('y = ', 'dynamic', 'List<dynamic>'); |
| } |
| } |
| |
| @reflectiveTest |
| class LibraryImportScopeTest extends ResolverTestCase { |
| void test_creation_empty() { |
| new LibraryImportScope(createDefaultTestLibrary()); |
| } |
| |
| void test_creation_nonEmpty() { |
| AnalysisContext context = AnalysisContextFactory.contextWithCore(); |
| String importedTypeName = "A"; |
| ClassElement importedType = new ClassElementImpl.forNode( |
| AstTestFactory.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]; |
| Scope scope = new LibraryImportScope(definingLibrary); |
| expect( |
| scope.lookup( |
| AstTestFactory.identifier3(importedTypeName), definingLibrary), |
| importedType); |
| } |
| |
| 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 |
| ]; |
| Scope scope = new LibraryImportScope(importingLibrary); |
| Element prefixedElement = scope.lookup( |
| AstTestFactory.identifier5(prefixName, typeName), importingLibrary); |
| expect(prefixedElement, same(prefixedType)); |
| Element nonPrefixedElement = |
| scope.lookup(AstTestFactory.identifier3(typeName), importingLibrary); |
| expect(nonPrefixedElement, same(nonPrefixedType)); |
| } |
| } |
| |
| @reflectiveTest |
| class LibraryScopeTest extends ResolverTestCase { |
| void test_creation_empty() { |
| new LibraryScope(createDefaultTestLibrary()); |
| } |
| |
| void test_creation_nonEmpty() { |
| AnalysisContext context = AnalysisContextFactory.contextWithCore(); |
| String importedTypeName = "A"; |
| ClassElement importedType = new ClassElementImpl.forNode( |
| AstTestFactory.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]; |
| Scope scope = new LibraryScope(definingLibrary); |
| expect( |
| scope.lookup( |
| AstTestFactory.identifier3(importedTypeName), definingLibrary), |
| importedType); |
| } |
| } |
| |
| @reflectiveTest |
| class PrefixedNamespaceTest extends ResolverTestCase { |
| void test_lookup_missing() { |
| ClassElement element = ElementFactory.classElement2('A'); |
| PrefixedNamespace namespace = new PrefixedNamespace('p', _toMap([element])); |
| expect(namespace.get('p.B'), isNull); |
| } |
| |
| void test_lookup_missing_matchesPrefix() { |
| ClassElement element = ElementFactory.classElement2('A'); |
| PrefixedNamespace namespace = new PrefixedNamespace('p', _toMap([element])); |
| expect(namespace.get('p'), isNull); |
| } |
| |
| void test_lookup_valid() { |
| ClassElement element = ElementFactory.classElement2('A'); |
| PrefixedNamespace namespace = new PrefixedNamespace('p', _toMap([element])); |
| expect(namespace.get('p.A'), same(element)); |
| } |
| |
| Map<String, Element> _toMap(List<Element> elements) { |
| Map<String, Element> map = new HashMap<String, Element>(); |
| for (Element element in elements) { |
| map[element.name] = element; |
| } |
| return map; |
| } |
| } |
| |
| @reflectiveTest |
| class ScopeTest extends ResolverTestCase { |
| void test_define_duplicate() { |
| Scope scope = new _RootScope(); |
| SimpleIdentifier identifier = AstTestFactory.identifier3('v'); |
| VariableElement element1 = ElementFactory.localVariableElement(identifier); |
| VariableElement element2 = ElementFactory.localVariableElement(identifier); |
| scope.define(element1); |
| scope.define(element2); |
| expect(scope.localLookup('v', null), same(element1)); |
| } |
| |
| void test_isPrivateName_nonPrivate() { |
| expect(Scope.isPrivateName("Public"), isFalse); |
| } |
| |
| void test_isPrivateName_private() { |
| expect(Scope.isPrivateName("_Private"), isTrue); |
| } |
| } |
| |
| class SourceContainer_ChangeSetTest_test_toString implements SourceContainer { |
| @override |
| bool contains(Source source) => false; |
| } |
| |
| /** |
| * 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>(); |
| |
| /** |
| * The TypeAnnotation nodes that were not resolved. |
| */ |
| List<TypeAnnotation> _unresolvedTypes = new List<TypeAnnotation>(); |
| |
| /** |
| * 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 (TypeAnnotation 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( |
| resolutionMap.staticTypeForExpression(expression).displayName); |
| buffer.write(", "); |
| buffer.write(resolutionMap |
| .propagatedTypeForExpression(expression) |
| .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 && |
| resolutionMap.staticTypeForExpression(node.prefix).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 visitTypeAnnotation(TypeAnnotation node) { |
| if (node.type == null) { |
| _unresolvedTypes.add(node); |
| } else { |
| _resolvedTypeCount++; |
| } |
| return super.visitTypeAnnotation(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. |
| // TODO(brianwilkerson) Not visiting the children means that we won't catch |
| // type arguments that were not resolved. |
| 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 resolutionMap |
| .elementDeclaredByCompilationUnit(rootCU) |
| .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 { |
| fail_for() async { |
| Source source = addSource(r''' |
| int f(List<int> list) { |
| num sum = 0; |
| for (num i = 0; i < list.length; i++) { |
| sum += list[i]; |
| } |
| }'''); |
| await computeAnalysisResult(source); |
| assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]); |
| } |
| |
| @override |
| void setUp() { |
| AnalysisOptionsImpl options = new AnalysisOptionsImpl(); |
| options.hint = false; |
| resetWith(options: options); |
| } |
| |
| test_assert_is() async { |
| Source source = addSource(r''' |
| int f(num n) { |
| assert (n is int); |
| return n & 0x0F; |
| }'''); |
| await computeAnalysisResult(source); |
| assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]); |
| } |
| |
| test_conditional_and_is() async { |
| Source source = addSource(r''' |
| int f(num n) { |
| return (n is int && n > 0) ? n & 0x0F : 0; |
| }'''); |
| await computeAnalysisResult(source); |
| assertNoErrors(source); |
| } |
| |
| test_conditional_is() async { |
| Source source = addSource(r''' |
| int f(num n) { |
| return (n is int) ? n & 0x0F : 0; |
| }'''); |
| await computeAnalysisResult(source); |
| assertNoErrors(source); |
| } |
| |
| test_conditional_isNot() async { |
| Source source = addSource(r''' |
| int f(num n) { |
| return (n is! int) ? 0 : n & 0x0F; |
| }'''); |
| await computeAnalysisResult(source); |
| assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]); |
| } |
| |
| test_conditional_or_is() async { |
| Source source = addSource(r''' |
| int f(num n) { |
| return (n is! int || n < 0) ? 0 : n & 0x0F; |
| }'''); |
| await computeAnalysisResult(source); |
| assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]); |
| } |
| |
| test_forEach() async { |
| Source source = addSource(r''' |
| int f(List<int> list) { |
| num sum = 0; |
| for (num n in list) { |
| sum += n & 0x0F; |
| } |
| }'''); |
| await computeAnalysisResult(source); |
| assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]); |
| } |
| |
| test_if_and_is() async { |
| Source source = addSource(r''' |
| int f(num n) { |
| if (n is int && n > 0) { |
| return n & 0x0F; |
| } |
| return 0; |
| }'''); |
| await computeAnalysisResult(source); |
| assertNoErrors(source); |
| } |
| |
| test_if_is() async { |
| Source source = addSource(r''' |
| int f(num n) { |
| if (n is int) { |
| return n & 0x0F; |
| } |
| return 0; |
| }'''); |
| await computeAnalysisResult(source); |
| assertNoErrors(source); |
| } |
| |
| test_if_isNot() async { |
| Source source = addSource(r''' |
| int f(num n) { |
| if (n is! int) { |
| return 0; |
| } else { |
| return n & 0x0F; |
| } |
| }'''); |
| await computeAnalysisResult(source); |
| assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]); |
| } |
| |
| test_if_isNot_abrupt() async { |
| Source source = addSource(r''' |
| int f(num n) { |
| if (n is! int) { |
| return 0; |
| } |
| return n & 0x0F; |
| }'''); |
| await computeAnalysisResult(source); |
| assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]); |
| } |
| |
| test_if_or_is() async { |
| Source source = addSource(r''' |
| int f(num n) { |
| if (n is! int || n < 0) { |
| return 0; |
| } else { |
| return n & 0x0F; |
| } |
| }'''); |
| await computeAnalysisResult(source); |
| assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]); |
| } |
| |
| test_localVar() async { |
| Source source = addSource(r''' |
| int f() { |
| num n = 1234; |
| return n & 0x0F; |
| }'''); |
| await computeAnalysisResult(source); |
| assertErrors(source, [StaticTypeWarningCode.UNDEFINED_OPERATOR]); |
| } |
| } |
| |
| @reflectiveTest |
| class SubtypeManagerTest { |
| /** |
| * The inheritance manager being tested. |
| */ |
| SubtypeManager _subtypeManager; |
| |
| /** |
| * The compilation unit element containing all of the types setup in each test. |
| */ |
| CompilationUnitElementImpl _definingCompilationUnit; |
| |
| void setUp() { |
| MemoryResourceProvider resourceProvider = new MemoryResourceProvider(); |
| AnalysisContext context = AnalysisContextFactory.contextWithCore( |
| resourceProvider: resourceProvider); |
| Source source = new FileSource(resourceProvider.getFile("/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(); |
| expect(() { |
| manager.exitScope(); |
| }, throwsStateError); |
| } |
| |
| void test_exitScope_oneScope() { |
| TypeOverrideManager manager = new TypeOverrideManager(); |
| manager.enterScope(); |
| manager.exitScope(); |
| expect(() { |
| manager.exitScope(); |
| }, throwsStateError); |
| } |
| |
| void test_exitScope_twoScopes() { |
| TypeOverrideManager manager = new TypeOverrideManager(); |
| manager.enterScope(); |
| manager.exitScope(); |
| manager.enterScope(); |
| manager.exitScope(); |
| expect(() { |
| manager.exitScope(); |
| }, throwsStateError); |
| } |
| |
| 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 { |
| fail_mergePropagatedTypesAtJoinPoint_1() async { |
| // https://code.google.com/p/dart/issues/detail?id=19929 |
| var code = 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 |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertTypeOfMarkedExpression(code, unit, null, typeProvider.dynamicType); |
| } |
| |
| fail_mergePropagatedTypesAtJoinPoint_2() async { |
| // https://code.google.com/p/dart/issues/detail?id=19929 |
| var code = 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 |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertTypeOfMarkedExpression(code, unit, null, typeProvider.dynamicType); |
| } |
| |
| fail_mergePropagatedTypesAtJoinPoint_3() async { |
| // https://code.google.com/p/dart/issues/detail?id=19929 |
| var code = 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 |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertTypeOfMarkedExpression(code, unit, null, typeProvider.numType); |
| } |
| |
| fail_mergePropagatedTypesAtJoinPoint_5() async { |
| // https://code.google.com/p/dart/issues/detail?id=19929 |
| var code = 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 |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertTypeOfMarkedExpression(code, unit, null, typeProvider.dynamicType); |
| } |
| |
| fail_mergePropagatedTypesAtJoinPoint_7() async { |
| // 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 |
| } |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| DartType t = findMarkedIdentifier(code, unit, "; // marker").propagatedType; |
| expect(typeProvider.intType.isSubtypeOf(t), isTrue); |
| expect(typeProvider.stringType.isSubtypeOf(t), isTrue); |
| } |
| |
| fail_mergePropagatedTypesAtJoinPoint_8() async { |
| // 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 |
| } |
| } |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| DartType t = findMarkedIdentifier(code, unit, "; // marker").propagatedType; |
| expect(typeProvider.intType.isSubtypeOf(t), isTrue); |
| expect(typeProvider.stringType.isSubtypeOf(t), isTrue); |
| } |
| |
| fail_propagatedReturnType_functionExpression() async { |
| // TODO(scheglov) disabled because we don't resolve function expression |
| String code = r''' |
| main() { |
| var v = (() {return 42;})(); |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertPropagatedAssignedType( |
| code, unit, typeProvider.dynamicType, typeProvider.intType); |
| } |
| |
| test_as() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| class A { |
| bool get g => true; |
| } |
| A f(var p) { |
| if ((p as A).g) { |
| return p; |
| } else { |
| return null; |
| } |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| ClassDeclaration classA = unit.declarations[0] as ClassDeclaration; |
| InterfaceType typeA = |
| resolutionMap.elementDeclaredByClassDeclaration(classA).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)); |
| } |
| |
| test_assert() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| class A {} |
| A f(var p) { |
| assert (p is A); |
| return p; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| ClassDeclaration classA = unit.declarations[0] as ClassDeclaration; |
| InterfaceType typeA = |
| resolutionMap.elementDeclaredByClassDeclaration(classA).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)); |
| } |
| |
| test_assignment() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| f() { |
| var v; |
| v = 0; |
| return v; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| 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, typeProvider.intType); |
| } |
| |
| test_assignment_afterInitializer() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| f() { |
| var v = 0; |
| v = 1.0; |
| return v; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| 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, typeProvider.doubleType); |
| } |
| |
| test_assignment_null() async { |
| String code = r''' |
| main() { |
| int v; // declare |
| v = null; |
| return v; // return |
| }'''; |
| CompilationUnit unit; |
| { |
| Source source = addSource(code); |
| TestAnalysisResult analysisResult = await computeAnalysisResult(source); |
| assertNoErrors(source); |
| verify([source]); |
| unit = analysisResult.unit; |
| } |
| { |
| SimpleIdentifier identifier = EngineTestCase.findNode( |
| unit, code, "v; // declare", (node) => node is SimpleIdentifier); |
| expect(identifier.staticType, typeProvider.intType); |
| expect(identifier.propagatedType, isNull); |
| } |
| { |
| SimpleIdentifier identifier = EngineTestCase.findNode( |
| unit, code, "v = null;", (node) => node is SimpleIdentifier); |
| expect(identifier.staticType, typeProvider.intType); |
| expect(identifier.propagatedType, isNull); |
| } |
| { |
| SimpleIdentifier identifier = EngineTestCase.findNode( |
| unit, code, "v; // return", (node) => node is SimpleIdentifier); |
| expect(identifier.staticType, typeProvider.intType); |
| expect(identifier.propagatedType, isNull); |
| } |
| } |
| |
| test_assignment_throwExpression() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| f() { |
| var v = 1; |
| v = throw 2; |
| return v; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source, noErrors: false); |
| 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, typeProvider.intType); |
| } |
| |
| test_CanvasElement_getContext() async { |
| if (previewDart2) { |
| return; |
| } |
| String code = r''' |
| import 'dart:html'; |
| main(CanvasElement canvas) { |
| var context = canvas.getContext('2d'); |
| }'''; |
| Source source = addSource(code); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| SimpleIdentifier identifier = EngineTestCase.findNode( |
| unit, code, "context", (node) => node is SimpleIdentifier); |
| expect(resolutionMap.propagatedTypeForExpression(identifier).name, |
| "CanvasRenderingContext2D"); |
| } |
| |
| test_forEach() async { |
| if (previewDart2) { |
| return; |
| } |
| String code = r''' |
| main() { |
| var list = <String> []; |
| for (var e in list) { |
| e; |
| } |
| }'''; |
| Source source = addSource(code); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| // in the declaration |
| { |
| SimpleIdentifier identifier = EngineTestCase.findNode( |
| unit, code, "e in", (node) => node is SimpleIdentifier); |
| expect(identifier.propagatedType, typeProvider.stringType); |
| } |
| // in the loop body |
| { |
| SimpleIdentifier identifier = EngineTestCase.findNode( |
| unit, code, "e;", (node) => node is SimpleIdentifier); |
| expect(identifier.propagatedType, typeProvider.stringType); |
| } |
| } |
| |
| test_forEach_async() async { |
| if (previewDart2) { |
| return; |
| } |
| String code = r''' |
| import 'dart:async'; |
| f(Stream<String> stream) async { |
| await for (var e in stream) { |
| e; |
| } |
| }'''; |
| Source source = addSource(code); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| // in the declaration |
| { |
| SimpleIdentifier identifier = EngineTestCase.findNode( |
| unit, code, "e in", (node) => node is SimpleIdentifier); |
| expect(identifier.propagatedType, typeProvider.stringType); |
| } |
| // in the loop body |
| { |
| SimpleIdentifier identifier = EngineTestCase.findNode( |
| unit, code, "e;", (node) => node is SimpleIdentifier); |
| expect(identifier.propagatedType, typeProvider.stringType); |
| } |
| } |
| |
| test_forEach_async_inheritedStream() async { |
| if (previewDart2) { |
| return; |
| } |
| // From https://github.com/dart-lang/sdk/issues/24191, this ensures that |
| // `await for` works for types where the generic parameter doesn't |
| // correspond to the type of the Stream's data. |
| String code = r''' |
| import 'dart:async'; |
| abstract class MyCustomStream<T> implements Stream<List<T>> {} |
| f(MyCustomStream<String> stream) async { |
| await for (var e in stream) { |
| e; |
| } |
| }'''; |
| Source source = addSource(code); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| InterfaceType listOfStringType = |
| typeProvider.listType.instantiate([typeProvider.stringType]); |
| // in the declaration |
| { |
| SimpleIdentifier identifier = EngineTestCase.findNode( |
| unit, code, "e in", (node) => node is SimpleIdentifier); |
| expect(identifier.propagatedType, equals(listOfStringType)); |
| } |
| // in the loop body |
| { |
| SimpleIdentifier identifier = EngineTestCase.findNode( |
| unit, code, "e;", (node) => node is SimpleIdentifier); |
| expect(identifier.propagatedType, equals(listOfStringType)); |
| } |
| } |
| |
| test_functionExpression_asInvocationArgument() async { |
| if (previewDart2) { |
| return; |
| } |
| 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); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| // k |
| FormalParameter kParameter = EngineTestCase.findNode( |
| unit, code, "k, ", (node) => node is SimpleFormalParameter); |
| expect(kParameter.identifier.propagatedType, typeProvider.intType); |
| SimpleIdentifier kIdentifier = EngineTestCase.findNode( |
| unit, code, "k;", (node) => node is SimpleIdentifier); |
| expect(kIdentifier.propagatedType, typeProvider.intType); |
| expect(kIdentifier.staticType, typeProvider.dynamicType); |
| // v |
| FormalParameter vParameter = EngineTestCase.findNode( |
| unit, code, "v)", (node) => node is SimpleFormalParameter); |
| expect(vParameter.identifier.propagatedType, typeProvider.stringType); |
| SimpleIdentifier vIdentifier = EngineTestCase.findNode( |
| unit, code, "v;", (node) => node is SimpleIdentifier); |
| expect(vIdentifier.propagatedType, typeProvider.stringType); |
| expect(vIdentifier.staticType, typeProvider.dynamicType); |
| } |
| |
| test_functionExpression_asInvocationArgument_fromInferredInvocation() async { |
| if (previewDart2) { |
| return; |
| } |
| 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); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| // k |
| FormalParameter kParameter = EngineTestCase.findNode( |
| unit, code, "k, ", (node) => node is SimpleFormalParameter); |
| expect(kParameter.identifier.propagatedType, typeProvider.intType); |
| // v |
| FormalParameter vParameter = EngineTestCase.findNode( |
| unit, code, "v)", (node) => node is SimpleFormalParameter); |
| expect(vParameter.identifier.propagatedType, typeProvider.stringType); |
| } |
| |
| test_functionExpression_asInvocationArgument_functionExpressionInvocation() async { |
| if (previewDart2) { |
| return; |
| } |
| String code = r''' |
| main() { |
| (f(String value)) {} ((v) { |
| v; |
| }); |
| }'''; |
| Source source = addSource(code); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| // v |
| FormalParameter vParameter = EngineTestCase.findNode( |
| unit, code, "v)", (node) => node is FormalParameter); |
| expect(vParameter.identifier.propagatedType, typeProvider.stringType); |
| expect(vParameter.identifier.staticType, typeProvider.dynamicType); |
| SimpleIdentifier vIdentifier = EngineTestCase.findNode( |
| unit, code, "v;", (node) => node is SimpleIdentifier); |
| expect(vIdentifier.propagatedType, typeProvider.stringType); |
| expect(vIdentifier.staticType, typeProvider.dynamicType); |
| } |
| |
| test_functionExpression_asInvocationArgument_keepIfLessSpecific() async { |
| if (previewDart2) { |
| return; |
| } |
| String code = r''' |
| class MyList { |
| forEach(f(Object value)) {} |
| } |
| f(MyList list) { |
| list.forEach((int v) { |
| v; |
| }); |
| }'''; |
| Source source = addSource(code); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| // v |
| FormalParameter vParameter = EngineTestCase.findNode( |
| unit, code, "v)", (node) => node is SimpleFormalParameter); |
| expect(vParameter.identifier.propagatedType, isNull); |
| expect(vParameter.identifier.staticType, typeProvider.intType); |
| SimpleIdentifier vIdentifier = EngineTestCase.findNode( |
| unit, code, "v;", (node) => node is SimpleIdentifier); |
| expect(vIdentifier.staticType, typeProvider.intType); |
| expect(vIdentifier.propagatedType, isNull); |
| } |
| |
| test_functionExpression_asInvocationArgument_notSubtypeOfStaticType() async { |
| String code = r''' |
| class A { |
| m(void f(int i)) {} |
| } |
| x() { |
| A a = new A(); |
| a.m(() => 0); |
| }'''; |
| Source source = addSource(code); |
| CompilationUnit unit = await _computeResolvedUnit(source, noErrors: false); |
| assertErrors(source, [StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE]); |
| // () => 0 |
| FunctionExpression functionExpression = EngineTestCase.findNode( |
| unit, code, "() => 0)", (node) => node is FunctionExpression); |
| expect((functionExpression.staticType as FunctionType).parameters.length, |
| same(0)); |
| expect(functionExpression.propagatedType, isNull); |
| } |
| |
| test_functionExpression_asInvocationArgument_replaceIfMoreSpecific() async { |
| if (previewDart2) { |
| return; |
| } |
| String code = r''' |
| class MyList<E> { |
| forEach(f(E value)) {} |
| } |
| f(MyList<String> list) { |
| list.forEach((Object v) { |
| v; |
| }); |
| }'''; |
| Source source = addSource(code); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| // v |
| FormalParameter vParameter = EngineTestCase.findNode( |
| unit, code, "v)", (node) => node is SimpleFormalParameter); |
| expect(vParameter.identifier.propagatedType, typeProvider.stringType); |
| expect(vParameter.identifier.staticType, typeProvider.objectType); |
| SimpleIdentifier vIdentifier = EngineTestCase.findNode( |
| unit, code, "v;", (node) => node is SimpleIdentifier); |
| expect(vIdentifier.propagatedType, typeProvider.stringType); |
| } |
| |
| test_Future_then() async { |
| if (previewDart2) { |
| return; |
| } |
| 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); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| // p1 |
| FormalParameter p1 = EngineTestCase.findNode( |
| unit, code, "p1) {", (node) => node is SimpleFormalParameter); |
| expect(p1.identifier.propagatedType, typeProvider.intType); |
| // p2 |
| FormalParameter p2 = EngineTestCase.findNode( |
| unit, code, "p2) {", (node) => node is SimpleFormalParameter); |
| expect(p2.identifier.propagatedType, typeProvider.doubleType); |
| // p3 |
| FormalParameter p3 = EngineTestCase.findNode( |
| unit, code, "p3) {", (node) => node is SimpleFormalParameter); |
| expect(p3.identifier.propagatedType, typeProvider.stringType); |
| } |
| |
| test_initializer() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| f() { |
| var v = 0; |
| return v; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| 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, typeProvider.dynamicType); |
| expect(variableName.propagatedType, typeProvider.intType); |
| } |
| // Type of 'v' in reference. |
| { |
| ReturnStatement statement = statements[1] as ReturnStatement; |
| SimpleIdentifier variableName = statement.expression as SimpleIdentifier; |
| expect(variableName.propagatedType, typeProvider.intType); |
| } |
| } |
| |
| test_initializer_dereference() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| f() { |
| var v = 'String'; |
| v.length; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source, noErrors: false); |
| 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, typeProvider.stringType); |
| } |
| |
| test_initializer_hasStaticType() async { |
| Source source = addSource(r''' |
| f() { |
| int v = 0; |
| return v; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| 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, 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, typeProvider.intType); |
| expect(variableName.propagatedType, isNull); |
| } |
| } |
| |
| test_initializer_hasStaticType_parameterized() async { |
| Source source = addSource(r''' |
| f() { |
| List<int> v = <int>[]; |
| return v; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| 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); |
| } |
| } |
| |
| test_initializer_null() async { |
| String code = r''' |
| main() { |
| int v = null; |
| return v; // marker |
| }'''; |
| CompilationUnit unit; |
| { |
| Source source = addSource(code); |
| unit = await _computeResolvedUnit(source); |
| } |
| { |
| SimpleIdentifier identifier = EngineTestCase.findNode( |
| unit, code, "v = null;", (node) => node is SimpleIdentifier); |
| expect(identifier.staticType, typeProvider.intType); |
| expect(identifier.propagatedType, isNull); |
| } |
| { |
| SimpleIdentifier identifier = EngineTestCase.findNode( |
| unit, code, "v; // marker", (node) => node is SimpleIdentifier); |
| expect(identifier.staticType, typeProvider.intType); |
| expect(identifier.propagatedType, isNull); |
| } |
| } |
| |
| test_initializer_throwExpression() async { |
| Source source = addSource(r''' |
| f() { |
| var v = throw 2; |
| return v; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source, noErrors: false); |
| FunctionDeclaration function = unit.declarations[0] as FunctionDeclaration; |
| BlockFunctionBody body = |
| function.functionExpression.body as BlockFunctionBody; |
| var statement = body.block.statements[0] as VariableDeclarationStatement; |
| SimpleIdentifier variableName = statement.variables.variables[0].name; |
| expect(variableName.propagatedType, isNull); |
| } |
| |
| test_invocation_target_prefixed() async { |
| addNamedSource('/helper.dart', ''' |
| library helper; |
| int max(int x, int y) => 0; |
| '''); |
| String code = ''' |
| import 'helper.dart' as helper; |
| main() { |
| helper.max(10, 10); // marker |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| SimpleIdentifier methodName = |
| findMarkedIdentifier(code, unit, "(10, 10); // marker"); |
| MethodInvocation methodInvoke = methodName.parent; |
| expect(methodInvoke.methodName.staticElement, isNotNull); |
| expect(methodInvoke.methodName.propagatedElement, isNull); |
| } |
| |
| test_is_conditional() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| class A {} |
| A f(var p) { |
| return (p is A) ? p : null; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| ClassDeclaration classA = unit.declarations[0] as ClassDeclaration; |
| InterfaceType typeA = |
| resolutionMap.elementDeclaredByClassDeclaration(classA).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)); |
| } |
| |
| test_is_if() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| class A {} |
| A f(var p) { |
| if (p is A) { |
| return p; |
| } else { |
| return null; |
| } |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| // prepare A |
| InterfaceType typeA; |
| { |
| ClassDeclaration classA = unit.declarations[0] as ClassDeclaration; |
| typeA = resolutionMap.elementDeclaredByClassDeclaration(classA).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)); |
| } |
| } |
| |
| test_is_if_lessSpecific() async { |
| Source source = addSource(r''' |
| class A {} |
| A f(A p) { |
| if (p is String) { |
| return p; |
| } else { |
| return null; |
| } |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| 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, isNull); |
| } |
| |
| test_is_if_logicalAnd() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| class A {} |
| A f(var p) { |
| if (p is A && p != null) { |
| return p; |
| } else { |
| return null; |
| } |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| ClassDeclaration classA = unit.declarations[0] as ClassDeclaration; |
| InterfaceType typeA = |
| resolutionMap.elementDeclaredByClassDeclaration(classA).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)); |
| } |
| |
| test_is_postConditional() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| class A {} |
| A f(var p) { |
| A a = (p is A) ? p : throw null; |
| return p; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| ClassDeclaration classA = unit.declarations[0] as ClassDeclaration; |
| InterfaceType typeA = |
| resolutionMap.elementDeclaredByClassDeclaration(classA).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)); |
| } |
| |
| test_is_postIf() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| class A {} |
| A f(var p) { |
| if (p is A) { |
| A a = p; |
| } else { |
| return null; |
| } |
| return p; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| ClassDeclaration classA = unit.declarations[0] as ClassDeclaration; |
| InterfaceType typeA = |
| resolutionMap.elementDeclaredByClassDeclaration(classA).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)); |
| } |
| |
| test_is_subclass() async { |
| 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; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| 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); |
| } |
| |
| test_is_while() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| class A {} |
| A f(var p) { |
| while (p is A) { |
| return p; |
| } |
| return p; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| ClassDeclaration classA = unit.declarations[0] as ClassDeclaration; |
| InterfaceType typeA = |
| resolutionMap.elementDeclaredByClassDeclaration(classA).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)); |
| } |
| |
| test_isNot_conditional() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| class A {} |
| A f(var p) { |
| return (p is! A) ? null : p; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| ClassDeclaration classA = unit.declarations[0] as ClassDeclaration; |
| InterfaceType typeA = |
| resolutionMap.elementDeclaredByClassDeclaration(classA).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)); |
| } |
| |
| test_isNot_if() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| class A {} |
| A f(var p) { |
| if (p is! A) { |
| return null; |
| } else { |
| return p; |
| } |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| ClassDeclaration classA = unit.declarations[0] as ClassDeclaration; |
| InterfaceType typeA = |
| resolutionMap.elementDeclaredByClassDeclaration(classA).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)); |
| } |
| |
| test_isNot_if_logicalOr() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| class A {} |
| A f(var p) { |
| if (p is! A || null == p) { |
| return null; |
| } else { |
| return p; |
| } |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source, noErrors: false); |
| ClassDeclaration classA = unit.declarations[0] as ClassDeclaration; |
| InterfaceType typeA = |
| resolutionMap.elementDeclaredByClassDeclaration(classA).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)); |
| } |
| |
| test_isNot_postConditional() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| class A {} |
| A f(var p) { |
| A a = (p is! A) ? throw null : p; |
| return p; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| ClassDeclaration classA = unit.declarations[0] as ClassDeclaration; |
| InterfaceType typeA = |
| resolutionMap.elementDeclaredByClassDeclaration(classA).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)); |
| } |
| |
| test_isNot_postIf() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| class A {} |
| A f(var p) { |
| if (p is! A) { |
| return null; |
| } |
| return p; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| ClassDeclaration classA = unit.declarations[0] as ClassDeclaration; |
| InterfaceType typeA = |
| resolutionMap.elementDeclaredByClassDeclaration(classA).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)); |
| } |
| |
| test_issue20904BuggyTypePromotionAtIfJoin_5() async { |
| // 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 |
| } |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| DartType tB = findMarkedIdentifier(code, unit, "; // B").propagatedType; |
| assertTypeOfMarkedExpression(code, unit, null, tB); |
| } |
| |
| test_issue20904BuggyTypePromotionAtIfJoin_6() async { |
| // 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 |
| } |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| DartType tB = findMarkedIdentifier(code, unit, "; // B").propagatedType; |
| assertTypeOfMarkedExpression(code, unit, null, tB); |
| } |
| |
| test_listLiteral_different() async { |
| Source source = addSource(r''' |
| f() { |
| var v = [0, '1', 2]; |
| return v[2]; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| 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); |
| } |
| |
| test_listLiteral_same() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| f() { |
| var v = [0, 1, 2]; |
| return v[2]; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| 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, typeProvider.listType.element); |
| List<DartType> typeArguments = propagatedType.typeArguments; |
| expect(typeArguments, hasLength(1)); |
| expect(typeArguments[0], typeProvider.dynamicType); |
| } |
| |
| test_mapLiteral_different() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| f() { |
| var v = {'0' : 0, 1 : '1', '2' : 2}; |
| return v; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| 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, typeProvider.mapType.element); |
| List<DartType> typeArguments = propagatedType.typeArguments; |
| expect(typeArguments, hasLength(2)); |
| expect(typeArguments[0], typeProvider.dynamicType); |
| expect(typeArguments[1], typeProvider.dynamicType); |
| } |
| |
| test_mapLiteral_same() async { |
| if (previewDart2) { |
| return; |
| } |
| Source source = addSource(r''' |
| f() { |
| var v = {'a' : 0, 'b' : 1, 'c' : 2}; |
| return v; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| 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, typeProvider.mapType.element); |
| List<DartType> typeArguments = propagatedType.typeArguments; |
| expect(typeArguments, hasLength(2)); |
| expect(typeArguments[0], typeProvider.dynamicType); |
| expect(typeArguments[1], typeProvider.dynamicType); |
| } |
| |
| test_mergePropagatedTypes_afterIfThen_different() async { |
| if (previewDart2) { |
| return; |
| } |
| String code = r''' |
| main() { |
| var v = 0; |
| if (v != null) { |
| v = ''; |
| } |
| return v; |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| { |
| SimpleIdentifier identifier = findMarkedIdentifier(code, unit, "v;"); |
| expect(identifier.propagatedType, null); |
| } |
| { |
| SimpleIdentifier identifier = findMarkedIdentifier(code, unit, "v = '';"); |
| expect(identifier.propagatedType, typeProvider.stringType); |
| } |
| } |
| |
| test_mergePropagatedTypes_afterIfThen_same() async { |
| if (previewDart2) { |
| return; |
| } |
| var code = r''' |
| main() { |
| var v = 1; |
| if (v != null) { |
| v = 2; |
| } |
| return v; // marker |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertTypeOfMarkedExpression(code, unit, null, typeProvider.intType); |
| } |
| |
| test_mergePropagatedTypes_afterIfThenElse_different() async { |
| var code = r''' |
| main() { |
| var v = 1; |
| if (v != null) { |
| v = 2; |
| } else { |
| v = '3'; |
| } |
| return v; // marker |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertTypeOfMarkedExpression(code, unit, null, null); |
| } |
| |
| test_mergePropagatedTypes_afterIfThenElse_same() async { |
| if (previewDart2) { |
| return; |
| } |
| var code = r''' |
| main() { |
| var v = 1; |
| if (v != null) { |
| v = 2; |
| } else { |
| v = 3; |
| } |
| return v; // marker |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertTypeOfMarkedExpression(code, unit, null, typeProvider.intType); |
| } |
| |
| test_mergePropagatedTypesAtJoinPoint_4() async { |
| // https://code.google.com/p/dart/issues/detail?id=19929 |
| if (previewDart2) { |
| return; |
| } |
| var code = r''' |
| f5(x) { |
| var y = []; |
| if (x) { |
| y = 0; |
| } else { |
| return y; |
| } |
| // Propagated type is [int] here: correct. |
| return y; // marker |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertTypeOfMarkedExpression(code, unit, null, typeProvider.intType); |
| } |
| |
| test_mutatedOutsideScope() async { |
| // 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; |
| }'''); |
| await computeAnalysisResult(source); |
| assertNoErrors(source); |
| } |
| |
| test_objectAccessInference_disabled_for_library_prefix() async { |
| String name = 'hashCode'; |
| addNamedSource('/helper.dart', ''' |
| library helper; |
| dynamic get $name => 42; |
| '''); |
| String code = ''' |
| import 'helper.dart' as helper; |
| main() { |
| helper.$name; // marker |
| }'''; |
| |
| CompilationUnit unit = await resolveSource(code); |
| SimpleIdentifier id = findMarkedIdentifier(code, unit, "; // marker"); |
| PrefixedIdentifier prefixedId = id.parent; |
| expect(id.staticType, typeProvider.dynamicType); |
| expect(prefixedId.staticType, typeProvider.dynamicType); |
| } |
| |
| test_objectAccessInference_disabled_for_local_getter() async { |
| String name = 'hashCode'; |
| String code = ''' |
| dynamic get $name => null; |
| main() { |
| $name; // marker |
| }'''; |
| |
| CompilationUnit unit = await resolveSource(code); |
| SimpleIdentifier getter = findMarkedIdentifier(code, unit, "; // marker"); |
| expect(getter.staticType, typeProvider.dynamicType); |
| } |
| |
| test_objectAccessInference_enabled_for_cascades() async { |
| if (previewDart2) { |
| return; |
| } |
| String name = 'hashCode'; |
| String code = ''' |
| main() { |
| dynamic obj; |
| obj..$name..$name; // marker |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| PropertyAccess access = |
| findMarkedIdentifier(code, unit, "; // marker").parent; |
| expect(access.staticType, typeProvider.dynamicType); |
| expect(access.realTarget.staticType, typeProvider.dynamicType); |
| } |
| |
| test_objectMethodInference_disabled_for_library_prefix() async { |
| String name = 'toString'; |
| addNamedSource('/helper.dart', ''' |
| library helper; |
| dynamic toString = (int x) => x + 42; |
| '''); |
| String code = ''' |
| import 'helper.dart' as helper; |
| main() { |
| helper.$name(); // marker |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| SimpleIdentifier methodName = |
| findMarkedIdentifier(code, unit, "(); // marker"); |
| MethodInvocation methodInvoke = methodName.parent; |
| expect(methodName.staticType, typeProvider.dynamicType); |
| expect(methodInvoke.staticType, typeProvider.dynamicType); |
| } |
| |
| test_objectMethodInference_disabled_for_local_function() async { |
| String name = 'toString'; |
| String code = ''' |
| main() { |
| dynamic $name = () => null; |
| $name(); // marker |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| |
| SimpleIdentifier identifier = findMarkedIdentifier(code, unit, "$name = "); |
| expect(identifier.staticType, typeProvider.dynamicType); |
| |
| SimpleIdentifier methodName = |
| findMarkedIdentifier(code, unit, "(); // marker"); |
| MethodInvocation methodInvoke = methodName.parent; |
| expect(methodName.staticType, typeProvider.dynamicType); |
| expect(methodInvoke.staticType, typeProvider.dynamicType); |
| } |
| |
| test_objectMethodInference_enabled_for_cascades() async { |
| if (previewDart2) { |
| return; |
| } |
| String name = 'toString'; |
| String code = ''' |
| main() { |
| dynamic obj; |
| obj..$name()..$name(); // marker |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| SimpleIdentifier methodName = |
| findMarkedIdentifier(code, unit, "(); // marker"); |
| MethodInvocation methodInvoke = methodName.parent; |
| |
| expect(methodInvoke.staticType, typeProvider.dynamicType); |
| expect(methodInvoke.realTarget.staticType, typeProvider.dynamicType); |
| } |
| |
| test_objectMethodOnDynamicExpression_doubleEquals() async { |
| // 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. |
| if (previewDart2) { |
| return; |
| } |
| var code = r''' |
| f1(x) { |
| var v = (x == x); |
| return v; // marker |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertTypeOfMarkedExpression(code, unit, null, typeProvider.boolType); |
| } |
| |
| test_objectMethodOnDynamicExpression_hashCode() async { |
| // https://code.google.com/p/dart/issues/detail?id=20342 |
| if (previewDart2) { |
| return; |
| } |
| var code = r''' |
| f1(x) { |
| var v = x.hashCode; |
| return v; // marker |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertTypeOfMarkedExpression(code, unit, null, typeProvider.intType); |
| } |
| |
| test_objectMethodOnDynamicExpression_runtimeType() async { |
| // https://code.google.com/p/dart/issues/detail?id=20342 |
| if (previewDart2) { |
| return; |
| } |
| var code = r''' |
| f1(x) { |
| var v = x.runtimeType; |
| return v; // marker |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertTypeOfMarkedExpression(code, unit, null, typeProvider.typeType); |
| } |
| |
| test_objectMethodOnDynamicExpression_toString() async { |
| // https://code.google.com/p/dart/issues/detail?id=20342 |
| if (previewDart2) { |
| return; |
| } |
| var code = r''' |
| f1(x) { |
| var v = x.toString(); |
| return v; // marker |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertTypeOfMarkedExpression(code, unit, null, typeProvider.stringType); |
| } |
| |
| test_propagatedReturnType_localFunction() async { |
| if (previewDart2) { |
| return; |
| } |
| String code = r''' |
| main() { |
| f() => 42; |
| var v = f(); |
| }'''; |
| CompilationUnit unit = await resolveSource(code); |
| assertPropagatedAssignedType( |
| code, unit, typeProvider.dynamicType, typeProvider.intType); |
| } |
| |
| test_query() async { |
| if (previewDart2) { |
| return; |
| } |
| 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]; |
| }'''); |
| CompilationUnit unit = await _computeResolvedUnit(source); |
| 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(resolutionMap.propagatedTypeForExpression(elements[0]).name, |
| "AnchorElement"); |
| expect(resolutionMap.propagatedTypeForExpression(elements[1]).name, |
| "AnchorElement"); |
| expect(resolutionMap.propagatedTypeForExpression(elements[2]).name, |
| "BodyElement"); |
| expect(resolutionMap.propagatedTypeForExpression(elements[3]).name, |
| "ButtonElement"); |
| expect(resolutionMap.propagatedTypeForExpression(elements[4]).name, |
| "DivElement"); |
| expect(resolutionMap.propagatedTypeForExpression(elements[5]).name, |
| "InputElement"); |
| expect(resolutionMap.propagatedTypeForExpression(elements[6]).name, |
| "SelectElement"); |
| expect(resolutionMap.propagatedTypeForExpression(elements[7]).name, |
| "DivElement"); |
| expect( |
| resolutionMap.propagatedTypeForExpression(elements[8]).name, "Element"); |
| expect( |
| resolutionMap.propagatedTypeForExpression(elements[9]).name, "Element"); |
| expect(resolutionMap.propagatedTypeForExpression(elements[10]).name, |
| "Element"); |
| } |
| |
| /** |
| * Return the resolved unit for the given [source]. |
| * |
| * If [noErrors] is not specified or is not `true`, [assertNoErrors]. |
| */ |
| Future<CompilationUnit> _computeResolvedUnit(Source source, |
| {bool noErrors: true}) async { |
| TestAnalysisResult analysisResult = await computeAnalysisResult(source); |
| if (noErrors) { |
| assertNoErrors(source); |
| verify([source]); |
| } |
| return analysisResult.unit; |
| } |
| } |
| |
| @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 futureOrType = |
| _classElement("FutureOr", 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, |
| futureOrType.element, |
| streamType.element |
| ]; |
| AnalysisContext context = AnalysisEngine.instance.createAnalysisContext(); |
| LibraryElementImpl coreLibrary = new LibraryElementImpl.forNode( |
| context, AstTestFactory.libraryIdentifier2(["dart.core"])); |
| coreLibrary.definingCompilationUnit = coreUnit; |
| LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode( |
| context, AstTestFactory.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.futureOrType, same(futureOrType)); |
| 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.streamType, same(streamType)); |
| 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(AstTestFactory.identifier3(typeName)); |
| element.supertype = superclassType; |
| 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( |
| AstTestFactory.identifier3(parameterNames[i])); |
| typeParameters[i] = typeParameter; |
| typeArguments[i] = new TypeParameterTypeImpl(typeParameter); |
| typeParameter.type = typeArguments[i]; |
| } |
| element.typeParameters = typeParameters; |
| } |
| } |
| return element; |
| } |
| } |
| |
| @reflectiveTest |
| class TypeResolverVisitorTest extends ParserTestCase { |
| /** |
| * The error listener to which errors will be reported. |
| */ |
| GatheringErrorListener _listener; |
| |
| /** |
| * The type provider used to access the types. |
| */ |
| TestTypeProvider _typeProvider; |
| |
| /** |
| * The library scope in which types are to be resolved. |
| */ |
| LibraryScope libraryScope; |
| |
| /** |
| * The visitor used to resolve types needed to form the type hierarchy. |
| */ |
| TypeResolverVisitor _visitor; |
| |
| fail_visitConstructorDeclaration() async { |
| _fail("Not yet tested"); |
| _listener.assertNoErrors(); |
| } |
| |
| fail_visitFunctionTypeAlias() async { |
| _fail("Not yet tested"); |
| _listener.assertNoErrors(); |
| } |
| |
| fail_visitVariableDeclaration() async { |
| _fail("Not yet tested"); |
| ClassElement type = ElementFactory.classElement2("A"); |
| VariableDeclaration node = AstTestFactory.variableDeclaration("a"); |
| AstTestFactory |
| .variableDeclarationList(null, AstTestFactory.typeName(type), [node]); |
| //resolve(node); |
| expect(node.name.staticType, same(type.type)); |
| _listener.assertNoErrors(); |
| } |
| |
| void setUp() { |
| _listener = new GatheringErrorListener(); |
| MemoryResourceProvider resourceProvider = new MemoryResourceProvider(); |
| InternalAnalysisContext context = AnalysisContextFactory.contextWithCore( |
| resourceProvider: resourceProvider); |
| Source librarySource = |
| new FileSource(resourceProvider.getFile("/lib.dart")); |
| LibraryElementImpl element = new LibraryElementImpl.forNode( |
| context, AstTestFactory.libraryIdentifier2(["lib"])); |
| element.definingCompilationUnit = |
| new CompilationUnitElementImpl("lib.dart"); |
| _typeProvider = new TestTypeProvider(); |
| libraryScope = new LibraryScope(element); |
| _visitor = new TypeResolverVisitor( |
| element, librarySource, _typeProvider, _listener, |
| nameScope: libraryScope); |
| } |
| |
| test_modeApi() async { |
| CompilationUnit unit = parseCompilationUnit(r''' |
| class C extends A with A implements A { |
| A f = new A(); |
| A m() { |
| A v1; |
| } |
| } |
| A f([A p = const A()]) { |
| A v2; |
| } |
| A V = new A(); |
| '''); |
| var unitElement = new CompilationUnitElementImpl('/test.dart'); |
| ClassElementImpl A = ElementFactory.classElement2('A'); |
| |
| // Build API elements. |
| { |
| var holder = new ElementHolder(); |
| unit.accept(new ApiElementBuilder(holder, unitElement)); |
| } |
| |
| // Resolve API types. |
| { |
| MemoryResourceProvider resourceProvider = new MemoryResourceProvider(); |
| InternalAnalysisContext context = AnalysisContextFactory.contextWithCore( |
| resourceProvider: resourceProvider); |
| var source = resourceProvider.getFile('/test.dart').createSource(); |
| var libraryElement = new LibraryElementImpl.forNode(context, null) |
| ..definingCompilationUnit = unitElement; |
| var libraryScope = new LibraryScope(libraryElement); |
| var visitor = new TypeResolverVisitor( |
| libraryElement, source, _typeProvider, _listener, |
| nameScope: libraryScope, mode: TypeResolverMode.api); |
| libraryScope.define(A); |
| unit.accept(visitor); |
| } |
| |
| // Top-level: C |
| { |
| var c = unit.declarations[0] as ClassDeclaration; |
| |
| // The extends/with/implements types are resolved. |
| expect(c.extendsClause.superclass.toString(), 'A'); |
| expect(c.withClause.mixinTypes[0].type.toString(), 'A'); |
| expect(c.implementsClause.interfaces[0].type.toString(), 'A'); |
| |
| { |
| var fd = c.members[0] as FieldDeclaration; |
| // The field type is resolved. |
| expect(fd.fields.type.type.toString(), 'A'); |
| // The type in the initializer is not resolved. |
| var f = fd.fields.variables[0]; |
| var fi = f.initializer as InstanceCreationExpression; |
| expect(fi.constructorName.type.type, isNull); |
| } |
| |
| { |
| var m = c.members[1] as MethodDeclaration; |
| // The return type is resolved. |
| expect(m.returnType.type.toString(), 'A'); |
| // The local variable type is not resolved. |
| var body = m.body as BlockFunctionBody; |
| var vd = body.block.statements.single as VariableDeclarationStatement; |
| expect(vd.variables.type.type, isNull); |
| } |
| } |
| |
| // Top-level: f |
| { |
| var f = unit.declarations[1] as FunctionDeclaration; |
| FunctionExpression fe = f.functionExpression; |
| // The return type is resolved. |
| expect(f.returnType.type.toString(), 'A'); |
| // The parameter type is resolved. |
| var pd = fe.parameters.parameters[0] as DefaultFormalParameter; |
| var p = pd.parameter as SimpleFormalParameter; |
| expect(p.type.type.toString(), 'A'); |
| // The parameter default is not resolved. |
| { |
| var pde = pd.defaultValue as InstanceCreationExpression; |
| expect(pde.constructorName.type.type, isNull); |
| } |
| // The local variable type is not resolved. |
| var body = fe.body as BlockFunctionBody; |
| var vd = body.block.statements.single as VariableDeclarationStatement; |
| expect(vd.variables.type.type, isNull); |
| } |
| |
| // Top-level: V |
| { |
| var vd = unit.declarations[2] as TopLevelVariableDeclaration; |
| // The type is resolved. |
| expect(vd.variables.type.toString(), 'A'); |
| // The initializer is not resolved. |
| VariableDeclaration v = vd.variables.variables[0]; |
| var vi = v.initializer as InstanceCreationExpression; |
| expect(vi.constructorName.type.type, isNull); |
| } |
| } |
| |
| test_modeLocal_noContext() async { |
| CompilationUnit unit; |
| _resolveTypeModeLocal(r''' |
| class C { |
| A f = new A(); |
| A m([A p = const A()]) { |
| A v; |
| } |
| } |
| A f([A p = const A()]) { |
| A v1 = new A(); |
| A f2(A p2) { |
| A v2; |
| } |
| } |
| A V = new A(); |
| A get G => new A(); |
| ''', (CompilationUnit u) { |
| unit = u; |
| return u; |
| }); |
| |
| // Top-level: C |
| { |
| var c = unit.declarations[0] as ClassDeclaration; |
| { |
| var fd = c.members[0] as FieldDeclaration; |
| // The type of "f" is not resolved. |
| expect(fd.fields.type.type, isNull); |
| // The initializer of "f" is resolved. |
| var f = fd.fields.variables[0]; |
| var fi = f.initializer as InstanceCreationExpression; |
| expect(fi.constructorName.type.type.toString(), 'A'); |
| } |
| { |
| var m = c.members[1] as MethodDeclaration; |
| // The return type of "m" is not resolved. |
| expect(m.returnType.type, isNull); |
| // The type of the parameter "p" is not resolved. |
| var pd = m.parameters.parameters[0] as DefaultFormalParameter; |
| var p = pd.parameter as SimpleFormalParameter; |
| expect(p.type.type, isNull); |
| // The default value of the parameter "p" is resolved. |
| var pdd = pd.defaultValue as InstanceCreationExpression; |
| expect(pdd.constructorName.type.type.toString(), 'A'); |
| // The type of "v" is resolved. |
| var mb = m.body as BlockFunctionBody; |
| var vd = mb.block.statements[0] as VariableDeclarationStatement; |
| expect(vd.variables.type.type.toString(), 'A'); |
| } |
| } |
| |
| // Top-level: f |
| { |
| var f = unit.declarations[1] as FunctionDeclaration; |
| // The return type of "f" is not resolved. |
| expect(f.returnType.type, isNull); |
| // The type of the parameter "p" is not resolved. |
| var fe = f.functionExpression; |
| var pd = fe.parameters.parameters[0] as DefaultFormalParameter; |
| var p = pd.parameter as SimpleFormalParameter; |
| expect(p.type.type, isNull); |
| // The default value of the parameter "p" is resolved. |
| var pdd = pd.defaultValue as InstanceCreationExpression; |
| expect(pdd.constructorName.type.type.toString(), 'A'); |
| // The type of "v1" is resolved. |
| var fb = fe.body as BlockFunctionBody; |
| var vd = fb.block.statements[0] as VariableDeclarationStatement; |
| expect(vd.variables.type.type.toString(), 'A'); |
| // The initializer of "v1" is resolved. |
| var v = vd.variables.variables[0]; |
| var vi = v.initializer as InstanceCreationExpression; |
| expect(vi.constructorName.type.type.toString(), 'A'); |
| // Local: f2 |
| { |
| var f2s = fb.block.statements[1] as FunctionDeclarationStatement; |
| var f2 = f2s.functionDeclaration; |
| // The return type of "f2" is resolved. |
| expect(f2.returnType.type.toString(), 'A'); |
| // The type of the parameter "p2" is resolved. |
| var f2e = f2.functionExpression; |
| var p2 = f2e.parameters.parameters[0] as SimpleFormalParameter; |
| expect(p2.type.type.toString(), 'A'); |
| // The type of "v2" is resolved. |
| var f2b = f2e.body as BlockFunctionBody; |
| var v2d = f2b.block.statements[0] as VariableDeclarationStatement; |
| expect(v2d.variables.type.type.toString(), 'A'); |
| } |
| } |
| |
| // Top-level: V |
| { |
| var vd = unit.declarations[2] as TopLevelVariableDeclaration; |
| // The type is not resolved. |
| expect(vd.variables.type.type, isNull); |
| // The initializer is resolved. |
| VariableDeclaration v = vd.variables.variables[0]; |
| var vi = v.initializer as InstanceCreationExpression; |
| expect(vi.constructorName.type.type.toString(), 'A'); |
| } |
| |
| // Top-level: G |
| { |
| var g = unit.declarations[3] as FunctionDeclaration; |
| // The return type is not resolved. |
| expect(g.returnType.type, isNull); |
| // The body is resolved. |
| var gb = g.functionExpression.body as ExpressionFunctionBody; |
| var ge = gb.expression as InstanceCreationExpression; |
| expect(ge.constructorName.type.type.toString(), 'A'); |
| } |
| } |
| |
| test_modeLocal_withContext_bad_methodBody() async { |
| expect(() { |
| _resolveTypeModeLocal(r''' |
| class C<T1> { |
| A m<T2>() { |
| T1 v1; |
| T2 v2; |
| } |
| } |
| ''', (CompilationUnit u) { |
| var c = u.declarations[0] as ClassDeclaration; |
| var m = c.members[0] as MethodDeclaration; |
| var mb = m.body as BlockFunctionBody; |
| return mb; |
| }); |
| }, throwsStateError); |
| } |
| |
| test_modeLocal_withContext_bad_topLevelVariable_declaration() async { |
| expect(() { |
| _resolveTypeModeLocal(r''' |
| var v = new A(); |
| ''', (CompilationUnit u) { |
| var tlv = u.declarations[0] as TopLevelVariableDeclaration; |
| return tlv.variables.variables[0]; |
| }); |
| }, throwsStateError); |
| } |
| |
| test_modeLocal_withContext_bad_topLevelVariable_initializer() async { |
| expect(() { |
| _resolveTypeModeLocal(r''' |
| var v = new A(); |
| ''', (CompilationUnit u) { |
| var tlv = u.declarations[0] as TopLevelVariableDeclaration; |
| return tlv.variables.variables[0].initializer; |
| }); |
| }, throwsStateError); |
| } |
| |
| test_modeLocal_withContext_class() async { |
| ClassDeclaration c; |
| _resolveTypeModeLocal(r''' |
| class C<T1> { |
| A m<T2>() { |
| T1 v1; |
| T2 v2; |
| } |
| } |
| ''', (CompilationUnit u) { |
| c = u.declarations[0] as ClassDeclaration; |
| return c; |
| }); |
| var m = c.members[0] as MethodDeclaration; |
| |
| // The return type of "m" is not resolved. |
| expect(m.returnType.type, isNull); |
| |
| var mb = m.body as BlockFunctionBody; |
| var ms = mb.block.statements; |
| |
| // The type of "v1" is resolved. |
| { |
| var vd = ms[0] as VariableDeclarationStatement; |
| expect(vd.variables.type.type.toString(), 'T1'); |
| } |
| |
| // The type of "v2" is resolved. |
| { |
| var vd = ms[1] as VariableDeclarationStatement; |
| expect(vd.variables.type.type.toString(), 'T2'); |
| } |
| } |
| |
| test_modeLocal_withContext_inClass_constructor() async { |
| ConstructorDeclaration cc; |
| _resolveTypeModeLocal(r''' |
| class C<T> { |
| C() { |
| T v1; |
| } |
| } |
| ''', (CompilationUnit u) { |
| var c = u.declarations[0] as ClassDeclaration; |
| cc = c.members[0] as ConstructorDeclaration; |
| return cc; |
| }); |
| |
| var ccb = cc.body as BlockFunctionBody; |
| var ccs = ccb.block.statements; |
| |
| // The type of "v" is resolved. |
| { |
| var vd = ccs[0] as VariableDeclarationStatement; |
| expect(vd.variables.type.type.toString(), 'T'); |
| } |
| } |
| |
| test_modeLocal_withContext_inClass_method() async { |
| MethodDeclaration m; |
| _resolveTypeModeLocal(r''' |
| class C<T1> { |
| A m<T2>() { |
| T1 v1; |
| T2 v2; |
| } |
| } |
| ''', (CompilationUnit u) { |
| var c = u.declarations[0] as ClassDeclaration; |
| m = c.members[0] as MethodDeclaration; |
| return m; |
| }); |
| |
| // The return type of "m" is not resolved. |
| expect(m.returnType.type, isNull); |
| |
| var mb = m.body as BlockFunctionBody; |
| var ms = mb.block.statements; |
| |
| // The type of "v1" is resolved. |
| { |
| var vd = ms[0] as VariableDeclarationStatement; |
| expect(vd.variables.type.type.toString(), 'T1'); |
| } |
| |
| // The type of "v2" is resolved. |
| { |
| var vd = ms[1] as VariableDeclarationStatement; |
| expect(vd.variables.type.type.toString(), 'T2'); |
| } |
| } |
| |
| test_modeLocal_withContext_topLevelFunction() async { |
| FunctionDeclaration f; |
| _resolveTypeModeLocal(r''' |
| A m<T>() { |
| T v; |
| } |
| ''', (CompilationUnit u) { |
| f = u.declarations[0] as FunctionDeclaration; |
| return f; |
| }); |
| |
| // The return type of "f" is not resolved. |
| expect(f.returnType.type, isNull); |
| |
| var fb = f.functionExpression.body as BlockFunctionBody; |
| var fs = fb.block.statements; |
| |
| // The type of "v" is resolved. |
| var vd = fs[0] as VariableDeclarationStatement; |
| expect(vd.variables.type.type.toString(), 'T'); |
| } |
| |
| test_modeLocal_withContext_topLevelVariable() async { |
| TopLevelVariableDeclaration v; |
| _resolveTypeModeLocal(r''' |
| A v = new A(); |
| ''', (CompilationUnit u) { |
| v = u.declarations[0] as TopLevelVariableDeclaration; |
| return v; |
| }); |
| |
| // The type of "v" is not resolved. |
| expect(v.variables.type.type, isNull); |
| |
| // The type of "v" initializer is resolved. |
| var |